
#include "threadsafe.h"
#include "miner.h"
#include "finder.h"
#include "table.h"
#include "time.h"
#include "parser.h"
#include "htmlobject.h"
#include "properties.h"
#include "hash.h"
#include "queue.h"

#include <stdio.h>
#include <stdlib.h>


   
#define INCLUDE_TO 2
#define INCLUDE_FROM 1

#define ORDER 1
#define AND	2
#define EQU 1
#define NTE  65
#define GTE  19
#define GT   18
#define LT    20
#define LTE   21
#define LIKE  6
#define LIKES 4
#define UNIQ  8
#define RANGE 16
#define FROMTO 32
#define NOTFROMTO 96
#define EXCLUDE 64
#define INCLUDE_ALL 128
#define MAXINT 0xffffffff

char* getstring(int m)
{
	switch(m){
		case LIKES:
		case LIKE:return("like");
		case LTE:return("<=");
		case LT:return ("<");
		case EQU:return("=");
		case NTE:return("<>");
		case GTE:return(">=");
		case GT:return(">");
		case UNIQ:return("is unique");
	}
	return("");
}

int compare(void* a, void* b, int type)
{
	if(type == Table::CHAR_TYPE){
        return(stricmp((char*) a, (char*) b));
	}else{
		if(type==Table::REAL_TYPE){
			if(*(double*)a==*(double*)b)
				return 0;
			else
				if(*(double*)a > *(double*)b){
					return(1);
				}else{
					return(-1);
				}
		}
		if(*(int*)a==*(int*)b)
			return 0;
		if(type==Table::TIME_TYPE){
			if(*(ULONG*)a > *(ULONG*)b){
				return(1);
			}else{
				return(-1);
			}
		}
		if(*(int*)a > *(int*)b){
			return(1);
		}else{
			return(-1);
		}
	}
}


int CompareCase(void* a, void* b, int type)
{
	if(type == Table::CHAR_TYPE){
        return(strcmp((char*) a, (char*) b));
	}else{
		if(type==Table::REAL_TYPE){
			if(*(double*)a==*(double*)b)
				return 0;
			else
				if(*(double*)a > *(double*)b){
					return(1);
				}else{
					return(-1);
				}
		}
		if(*(int*)a==*(int*)b)
			return 0;
		if(type==Table::TIME_TYPE){
			if(*(ULONG*)a > *(ULONG*)b){
				return(1);
			}else{
				return(-1);
			}
		}
		if(*(int*)a > *(int*)b){
			return(1);
		}else{
			return(-1);
		}
	}
}


int  printFilename(char *printBuffer,int recId,int fieldId)
{
	char *frmts="%08d%08d";
	if(fieldId<1000){
		frmts="%08d%03d";
	}
	return	snprintf(printBuffer,20,frmts,recId,fieldId);
}

int checkValidRelation(char* dbname,char* table,int rec);

int Table::matchSelection(char *tmp,Field *f,char type, char *v1,char* v2)
{
   if(tmp==0 || f==0)
      return 0;
   int match=0;
   recordInfo* tmpNode=(recordInfo*)(tmp+f->offset);
   char* fv = tmp+getFieldOffset(f);
   switch (type&~(EXCLUDE|UNIQ)) {
   case 0:
     	 match=(tmpNode->centerWeight!=-1);
      	 break;
      case EQU:
         if(v1)
          match = (compare(fv,v1,f->type)==0);
         break;
      case FROMTO+INCLUDE_FROM:
         if(v1)
          match = ((compare(fv,v1,f->type)>=0)&&((v2==0) || (compare(fv,v2,f->type)<0)));
        break;
      case FROMTO+INCLUDE_TO:
         if(v2)
          match = (((v1==0) || (compare(fv,v1,f->type)>0))&&(compare(fv,v2,f->type)<=0));
        break;
      case FROMTO+INCLUDE_FROM+INCLUDE_TO:
         if(v1 && v2)
          match = ((compare(fv,v1,f->type)>=0)&&(compare(fv,v2,f->type)<=0));
        break;
      case FROMTO:
         if(v1 || v2)
          match = ( ((v1==0) || (compare(fv,v1,f->type)>0)) && ((v2==0) || (compare(fv,v2,f->type)<0)) );
         else
          match=1;
        break;
      } /* endswitch */
   if(type&UNIQ){
         if(tmpNode->centerWeight==-1)
            match=0;
   }
   if(type&EXCLUDE){
	   return !match;
   }else{
	   return match;
   }
}

int Selection::equals(Field *f,char typ, char *v1,char* v2)
{
   int match=0;
   if((f==fld) && (typ==type)){
      switch (type&~(EXCLUDE|UNIQ)) {
      case 0:
         match=1;
         break;
      case EQU:
          if(v1)
          match= (compare(v1,*from,f->type)==0);
         break;
      case FROMTO+INCLUDE_FROM:
      case FROMTO+INCLUDE_TO:
      case FROMTO+INCLUDE_FROM+INCLUDE_TO:
      case FROMTO:
         if(v1 && v2 && from && to)
          match=((compare(v1,*from,f->type)==0)&&(compare(v2,*to,f->type)==0));
         else
          if((v2==0) && (to==0) && (v1 && from))
             match=(compare(v1,*from,f->type)==0);
         else
          if((v1==0) && (from==0) && (v2 && to))
             match=(compare(v2,*to,f->type)==0);
          else
             if((v1==0) && (from==0) && (v2==0) && (to==0))
                match=1;
        break;
      } /* endswitch */
    }
   return match;
}


Buffer* Selection::getBuffer()
{
	if(cache && (cacheSize>0)){
		return new Buffer(*cache,cacheSize*sizeof(int));
	}
	return 0;
}


int Selection::getNext(int current, int offset,int save)
{
	if((cache==0) || (cacheSize<=0))
		return 0;
	int *x=(int*)((char*)*cache);
	int total=cacheSize;
	int newpos=pos;
	if(current==0){
		if(offset<0){
			newpos=total-1;
			offset++;
		}
		else{
			newpos=0;
			offset--;
		}
		current=x[newpos];
		if(offset==0){
			if(save==0)
				pos=newpos;
			return current;
		}
	}
	if(current!=x[newpos]){
		for(newpos=0;newpos<total;newpos++)
			if(current==x[newpos])
				break;
	}
	if(current==x[newpos]){
		int tmp=newpos+offset;
		if(tmp>=total)
			current=x[newpos=(total-1)];
		else
			if(tmp<0)
				current=x[newpos=0];
			else
				current=x[newpos=tmp];
			if(save==0)  
				pos=newpos;
	}
	return current;
}


int Selection::remove(int rec,int rep)
{
	if((cache==0) || (cacheSize<=0)){
		return 0;
	}
	int *d=(int*)((char*)*cache);
	int b=0;
	for(;b<cacheSize;++b){
		if(d[b]==rec)
			break;
	}
	if(b==cacheSize){
		return 0;
	}
	if(rep && (type&UNIQ)){
		d[b]=rep;
		return 1;
	}
	cacheSize--;
	Buffer *tmp=0;
	int *s=d;
	if((cacheSize%256)==0){
		if(cacheSize==0){
			delete cache;
			cache=0;
			return 1;
		}
		if(((cache->getSize()/sizeof(int))-cacheSize)>512){
			tmp=cache;
			cache=new Buffer((cacheSize+128)*sizeof(int));
			s=(int*)((char*)*cache);
			if(b>0)
				memcpy(s,d,b*sizeof(int));
		}
	}
	if(cacheSize>b)
		memcpy(s+b,d+b+1,(cacheSize-b)*sizeof(int));
	delete tmp;
	return 1;
}


int Selection::add(int before,int rec,int rep)
{
	Buffer *tmp=0;
	if(cache){
        int *d=(int*)((char*)*cache);
		int b=0;
		if(before){
			for(;b<cacheSize;++b)
				if(d[b]==before)
					break;
		}else
			b=cacheSize;
        if(type&UNIQ){
           if((b > 0) && (d[b-1]==rep)){
              d[b-1]=rec;
              return 1;
            }
        }
        if(cache->getSize()<=(int)(cacheSize*sizeof(int))){
			int *s=d;
			tmp=cache;
			cache=new Buffer(sizeof(int)*(256+cacheSize));
			d=(int*)((char*)*cache);
			if(b>0)
				memcpy(d,s,b*sizeof(int));
			if(b<cacheSize)
				memcpy(d+b+1,s+b,(cacheSize-b)*sizeof(int));
        }else
			if(b<cacheSize)
				memmove(d+b+1,d+b,(cacheSize-b)*sizeof(int));
        d[b]=rec;
        cacheSize++;
	}
	delete tmp;
	return 1;
}


Buffer* Table::getSelectionFromCache(Field *f, char type, char *from, char* to,int*last)
{
	Buffer *p=0;
	lock();
	for(int i=0;i<MAXSELECTION;++i){
		if(cachedSelection[i]!=0){
			if(cachedSelection[i]->equals(f,type,from,to)){
				cachedSelection[i]->setAccessTime();
				if(last==0)
					p=cachedSelection[i]->getBuffer();
				else
					*last=cachedSelection[i]->getNext(0,1);
				break;
			}
		}
	}
	release();
	return p;
}

void  Table::addSelection(Selection *z)
{
	lock();
    int s=-1,j=-1;
	for(int i=0;i<MAXSELECTION;++i){
		if(cachedSelection[i]==0){
			if(j==-1){
				j=i;
			}
		}else{
            if(cachedSelection[i]->equals(z->getField(),z->getType(),z->getFrom(),z->getTo())){
				release();
				delete z;
				return;
			}
			if(cachedSelection[i]->isLocked()==0){
				if(s!=-1){
					if((j==-1) && (cachedSelection[i]->getAccessTime() < cachedSelection[s]->getAccessTime()))
						s=i;
				}else
					s=i;
			}
		}
	}
	if((j==-1) && ((s!=-1) && (cachedSelection[s]->getAccessTime() < z->getAccessTime()))){
		delete cachedSelection[s];
		j=s;
	}
	if(j!=-1)
		cachedSelection[j]=z;
	else
		delete z;
	release();
}


int Table::unlockTable(int r,char* id)
{
	lock();
	if (locked==1){
		if(wt && (strcmp(wt->waitingId,id)==0)){
			locked=0;
			wt->waitingThread->Resume();
		}
	}
	release();
	return locked;
}

void unlockTables(char* id)
{
}

int validSeed(char*);

int Table::lockTable(int r,char* id,Runnable *thread,int locknow)
{
	lock();
	if(locknow){
		while(locked>=0){
			LOCWAIT	*W=new LOCWAIT();
			W->waitingThread=thread;
			strcpy(W->waitingId,id);
			W->next=0;
			LOCWAIT *last=0;
			for(LOCWAIT *w=wt;w!=0;w=w->next)
				last=w;
			if(last)
				last->next=W;
			else
				wt=W;
			release();
			thread->Suspend();
			lock();
			if((wt!=0) && (wt->waitingThread==thread) && validSeed(wt->waitingId)){
				W=wt;
				wt=wt->next;
				delete W;
			}else{
				release();
				return 0;
			}
		}
		locked=1;
	}
	release();
	return locked;
}


int Table::getMin(Field *f)
{
getMIN:
    int node=f->root;
	int level=0;
    if(node){
		char* tmp=mustGetRecordCached(node);
		recordInfo* tmpNode=(recordInfo*)(tmp+f->offset);
		while(tmpNode->left && level++<128){
			node=tmpNode->left;
			tmp=mustGetRecordCached(node);
			tmpNode=(recordInfo*)(tmp+f->offset);
		}
	}
	if(level>=128){
		RepairTableOnline();
		goto getMIN;
	}
    return node;
}


int Table::getMax(Field *f)
{
getMAX:
    int node=f->root;
	int level=0;
    if(node){
		char* tmp=mustGetRecordCached(node);
		recordInfo* tmpNode=(recordInfo*)(tmp+f->offset);
		while(tmpNode->right && level++<128){
			node=tmpNode->right;
			tmp=mustGetRecordCached(node);
			tmpNode=(recordInfo*)(tmp+f->offset);
		}
	}
	if(level>=128){
		RepairTableOnline();
		goto getMAX;
	}
    return node;
}

int Table::searchTree(char*  val,Field *f)
{
	if(f->type==FILE_TYPE || f->type==BIN_TYPE)
		return 0;
	lock();
searchTREE:
	int recId=f->root;
	int of=getFieldOffset(f);
	int level=0;
	while(recId!=0 && level++<128){
		char *recBuff=mustGetRecordCached(recId);
		recordInfo* node = (recordInfo*)(recBuff+f->offset);
		int d=compare(val,recBuff+of,f->type);
		if(d<0){
			recId=node->left;
		}
		else
			if(d>0){
				recId=node->right;
			}
			else
				break;
    }
	if(level>=128){
		RepairTableOnline();
		goto searchTREE;
	}
	release();
    return recId;
}


void caravanlog(char* s)
{
	RealFile *f=new RealFile((*serverConfig)["documents"],"caravanlog.txt");
	if (f->exists())
		f->seekEND();
	else
		f->create();
	Time *t=new Time();
	f->write(t->printable());
	delete t;
	f->write(" !! ");
	f->write(s);
	f->write("\r\n");
	delete f;
}



int Table::modifyNode(int recId,Field *f)
{
    if(f->type==FILE_TYPE || f->type==BIN_TYPE)
		return 0;
    char *rec=getRecordCached(recId);
    if(rec==0)
		return 0;
    char *tmpRec;
    recordInfo* tmpNode;
    recordInfo* node=(recordInfo*)(rec+f->offset);
    int change=node->center;
	if((change==0) && node->parent){
		tmpRec=mustGetRecordCached(node->parent);
		tmpNode=(recordInfo*)(tmpRec+f->offset);
		if(tmpNode->center == recId){
			change=1;
		}
	}
    if(change==0){
		int dataOffset=getFieldOffset(f);
		if(node->right && node->left){
			change=1;
			tmpRec=mustGetRecordCached(node->right);
			if(compare(tmpRec+dataOffset,rec+dataOffset,f->type)>0){
				char *rightNode=tmpRec;
				tmpRec=mustGetRecordCached(node->left);
				if(compare(tmpRec+dataOffset,rec+dataOffset,f->type)<0){
					int oppNode;
					while(change && ((oppNode=((recordInfo*)(tmpRec+f->offset))->right)!=0)){
						tmpRec=mustGetRecordCached(oppNode);
						change=(compare(tmpRec+dataOffset,rec+dataOffset,f->type)<0);
					}
					tmpRec=rightNode;
					while(change && ((oppNode=((recordInfo*)(tmpRec+f->offset))->left)!=0)){
						tmpRec=mustGetRecordCached(oppNode);
						change=(compare(tmpRec+dataOffset,rec+dataOffset,f->type)>0);
					}
					change=!change;
				}
			}
		}else{
			if(node->right){
				tmpRec=mustGetRecordCached(node->right);
				change=!(compare(tmpRec+dataOffset,rec+dataOffset,f->type)>0);
			}else{
				if(node->left){
					tmpRec=mustGetRecordCached(node->left);
					change=!(compare(tmpRec+dataOffset,rec+dataOffset,f->type)<0);
				}
			}
			if((change==0) && node->parent){
				tmpRec=mustGetRecordCached(node->parent);
				tmpNode=(recordInfo*)(tmpRec+f->offset);
				if(tmpNode->right == recId){
					change=!(compare(tmpRec+dataOffset,rec+dataOffset,f->type)<0);
				}else{
					if(tmpNode->left == recId){
						change=!(compare(tmpRec+dataOffset,rec+dataOffset,f->type)>0);
					}
				}
				if(change==0){
					int child=node->parent;
					int parent;
					if(tmpNode->left==recId){
						while(tmpNode->parent){
							tmpRec=mustGetRecordCached(parent=tmpNode->parent);
							tmpNode=(recordInfo*)(tmpRec+f->offset);
							if(tmpNode->right==child){
								change=!(compare(tmpRec+dataOffset,rec+dataOffset,f->type)<0);
								break;
							}
							child=parent;
						}
					}else{
						if(tmpNode->right==recId){
							while(tmpNode->parent){
								tmpRec=mustGetRecordCached(parent=tmpNode->parent);
								tmpNode=(recordInfo*)(tmpRec+f->offset);
								if(tmpNode->left==child){
									change=!(compare(tmpRec+dataOffset,rec+dataOffset,f->type)>0);
									break;
								}
								child=parent;
							}
						}
					}
				}
			}
		}
    }
	if(change){
		int pr=f->root;
		int pu=f->unodes;
		int r=deleteNode(recId,f);
		if(r>=0){
			r=insertNode(recId,f);
			if(r>=0){
				return (pu!=f->unodes || pr!=f->root);
			}
		}
		return r;
	}
	return 0;
}

void Table::updateSelections(char *current,int recId,htmlBuffer *fieldList,char* old)
{
	int i;
	Field *f;
	Selection *s;
	int slist[MAXSELECTION];
	int rm=0;
	if(old){
		for(i=0;i<MAXSELECTION;++i){
			s=cachedSelection[i];
			if(s!=0){
				f=s->getField();
				for(htmlBuffer *h=fieldList;h!=0;h=h->next){
					if(stricmp(f->fieldName,*h)==0){
						recordInfo* node=(recordInfo*)(old+f->offset);
						if(matchSelection(old,f,s->getType(),s->getFrom(),s->getTo())){
							s->remove(recId,node->center);
							slist[rm++]=i;
						}
						break;
					}
				}
			}
		}
	}
	for(i=0;i<MAXSELECTION;++i){
		s=cachedSelection[i];
		if((s!=0) && (s->getType()==EQU)){
			f=s->getField();
			htmlBuffer *h=fieldList;
			for(;h!=0;h=h->next){
				if(stricmp(f->fieldName,*h)==0)
					break;
			}
			if((h!=0) || (fieldList==0)){
				if(matchSelection(current,f,s->getType(),s->getFrom(),s->getTo())){
					recordInfo* node=(recordInfo*)(current+f->offset);
					s->lockSelection(1);
					s->add(getNextRangeAsc(recId,f,s->getType()&UNIQ),recId,node->center);
					s->lockSelection(0);
				}
			}
		}
	}
	for(i=0;i<MAXSELECTION;++i){
		s=cachedSelection[i];
		if((s!=0) && (s->getType()!=EQU)){
			f=s->getField();
			htmlBuffer *h=fieldList;
			for(;h!=0;h=h->next){
				if(stricmp(f->fieldName,*h)==0)
					break;
			}
			if((h!=0) || (fieldList==0)){
				if(matchSelection(current,f,s->getType(),s->getFrom(),s->getTo())){
					recordInfo* node=(recordInfo*)(current+f->offset);
					s->lockSelection(1);
					s->add(getNextRangeAsc(recId,f,s->getType()&UNIQ),recId,node->center);
					s->lockSelection(0);
				}
			}
		}
	}
	for(i=0;i<rm;++i){
		s=cachedSelection[slist[i]];
		if(s && (s->getTotal()<MINCACHESIZE)){
			cachedSelection[slist[i]]=0;
			delete s;
		}
	}
}


int Table::moveNode(int move,int pos,char* fieldName)
{
    Field *f=getField(fieldName);
    if((f==0) || (f->type==FILE_TYPE) || (move==pos))
		return 0;
    lock();
    char *recMove=getRecordCached(move);
	recordInfo* node=(recordInfo*)(recMove+f->offset);
    char *recPos=getRecordCached(pos);
    if(recMove==0 || recPos==0){
        release();
		return 0;
    }
    int dataOffset=getFieldOffset(f);
    int i=0;
    for(;i<MAXSELECTION;++i)  {
		Selection* s=cachedSelection[i];
		if(s){
			Field* fs=s->getField();
			if((fs==f) && matchSelection(recMove,f,s->getType(),s->getFrom(),s->getTo())){
				s->remove(move,node->center);
				if(s->getTotal()<MINCACHESIZE){
					cachedSelection[i]=0;
					delete s;
				}
			}
		}
	}
	int pr=f->root;
    int pu=f->unodes;
    deleteNode(move,f);
    recMove=mustGetRecordCached(move);
	node=(recordInfo*)(recMove+f->offset);
    memset(node,0,sizeof(recordInfo));
    i=getFieldDim(recPos,f);
    memcpy(recMove+dataOffset,recPos+dataOffset,i*f->size*elementSize(f->type));
    putFieldDim(recMove,f,i);
    dbf->bufferedPut(recMove,move);
    if((insertNode(move,f,pos)>0) || (pr!=f->root) || (pu!=f->unodes)){
		char *tmpHeader=dbf->getHeader();
		memcpy(tmpHeader+f->hdOffset,f,FIELDSIZE);
		dbf->bufferedPutHeader();
	}
    dbf->flushDat();
	htmlBuffer *fh=new htmlBuffer(f->fieldName);
	updateSelections(recMove,move,fh);
	delete fh;
    release();
    return 0;
}




void Table::deleteRelation(char*relField,int relation)
{
	for( SField *sf=fields;sf!=0; sf = (SField *)(((Field *)*sf) ->next)){
		if((((Field *)*sf)->type==INDEX_TYPE) && (stricmp(relField,((Field *)*sf)->tableName)==0)){
			Buffer *tmp=getEqualsBuffer((char*)&relation,(Field *)*sf);
			if(tmp){
				int *x=(int*)((char*)*tmp);
				int t=tmp->getSize()/sizeof(int);
				htmlObject* v=new htmlObject();
				v->putValue(((Field *)*sf)->fieldName,"");
				while(t>0)
					updateRecord(v,x[--t],2);
				delete v;
			}
			delete tmp;
		}
	}
}


int Table::getNextRangeAsc(int newnode,Field *f,int unique)
{
	int node;
	lock();
getNextRangeASC:
	int current=newnode;
	int level=0;
	if(current==0){
		node = getMin(f);
	}else{
		node=0;
		char* tmp=getRecordCached(current);
		if(tmp){
			recordInfo* tmpNode=(recordInfo*)(tmp+f->offset);
			if(tmpNode->centerWeight==-1){
				release();
				return tmpNode->parent;
			}
			if(tmpNode->right){
				tmp=mustGetRecordCached(node=tmpNode->right);
				tmpNode=(recordInfo*)(tmp+f->offset);
				while(tmpNode->left && (level++<128)){
					tmp=mustGetRecordCached(node=tmpNode->left);
					tmpNode=(recordInfo*)(tmp+f->offset);
				}
			}else{
				while((level++<128) && ((node=tmpNode->parent)!=0)){
					tmp=mustGetRecordCached(node);
					tmpNode=(recordInfo*)(tmp+f->offset);
					if(tmpNode->left==current)
						break;
					current=node;
				}
			}
		}
	}
	if(level>=128){
		RepairTableOnline();
		goto getNextRangeASC;
	}
	release();
	if(node){
		if(unique){
			return node;
		}else{
			return getLastEqual(node,f);
		}
	}else{
		return 0;
	}
}


int Table::getNextRangeDesc(int newnode,Field *f,int unique)
{
	lock();
getNextRangeDESC:
	int node;
	int current=newnode;
	int level=0;
	if(current==0)
		node=getMax(f);
	else{
		char* tmp=getRecordCached(current);
		if(tmp){
			recordInfo* tmpNode=(recordInfo*)(tmp+f->offset);
			if(!unique){
				if(tmpNode->center){
					release();
					return tmpNode->center;
				}else{
					if(tmpNode->centerWeight ==-1){
						current=searchTree(tmp+getFieldOffset(f),f);
						tmp=mustGetRecordCached(current);
						tmpNode=(recordInfo*)(tmp+f->offset);
					}
				}
			}
			if(tmpNode->left){
				tmp=mustGetRecordCached(node=tmpNode->left);
				tmpNode=(recordInfo*)(tmp+f->offset);
				while(tmpNode->right && level++<128){
					tmp=mustGetRecordCached(node=tmpNode->right);
					tmpNode=(recordInfo*)(tmp+f->offset);
				}
			}else{
				while((level++<128) && ((node=tmpNode->parent)!=0)){
					tmp=mustGetRecordCached(node);
					tmpNode=(recordInfo*)(tmp+f->offset);
					if(tmpNode->right==current)
						break;
					current=node;
				}
			}
		}
	}
	if(level>=128){
		RepairTableOnline();
		goto getNextRangeDESC;
	}
	release();
	return node;
}


int intcmp(const void* a,const void* b)
{
    if(*(int*)a != *(int*)b){
		if(*(ULONG*)a > *(ULONG*)b){
			return(1);
		}else{
			return(-1);
		}
	}
	return 0;
}


void sortList(Buffer *m)
{
  qsort(*m,m->getSize()/sizeof(int),sizeof(int),intcmp);
}




int findinList(Buffer *store,int n)
{
	if(store==0)
		return 0;
	int m;
	int b=0;
	int e=(store->getSize()/sizeof(int))-1;
	int *d=(int*)((char*)*store);
	while(e>=b){
		m = (b+e)/2;
		if(d[m]<n)
			b=m+1;
		else
			if(d[m]>n)
				e=m-1;
			else
				return 1;
	}
	return 0;
}



Buffer* Table::getRangeBuffer(int start,int end,Field *f,int unique,int count,int order,LinkedBuffer* fs)
{
	if(count==0)
		return 0;
	lock();
getRangeBUFFER:
	int level=0;
	if(start==0)
		start = getMin(f);
	if(start==0){
		release();
		return 0;
	}
	Buffer *r=0;
	Buffer *buff=new Buffer(getRecordSize());
	char* tmp=*buff;
getStart:
	if(getRecordFromCache(start,buff)==0){
abortRb:
		release();
		delete buff;
		delete r;
		return 0;
	}
	int fo=getFieldOffset(f);
	recordInfo* tmpNode=(recordInfo*)(tmp+f->offset);
	if(tmpNode->centerWeight==-1){
		start=searchTree(tmp+fo,f);
		goto getStart;
	}
	Buffer* buf=new Buffer((count+64)*sizeof(int));
	int maxcount=buf->getSize()/sizeof(int);
	int *x=(int*)((char*)*buf);
	*x=start;
	int incount=1;
	while( (incount < count) ){
		level=0;
		if(!unique){
			if(tmpNode->center){
				Buffer *qx;
				if(fs){
					qx=getEqualsBuffer(tmp+fo,f,fs,order,&r,start);
					if(r==0)
						fs=0;
				}
				else
					qx=getEqualsBuffer(tmp+fo,f,start);
				if(qx!=0){
					incount--;
					int an=qx->getSize()/sizeof(int);
					if((an > 0) && ((an+incount)<(maxcount))){
						memcpy(x+incount,*qx,qx->getSize());
						incount+=an;
					}
				}
				delete qx;
			}	
		}
		if(start==end)
			break;
		if(tmpNode->right){
			if(getRecordFromCache(start=tmpNode->right,buff)==0){
				delete buf;
				goto abortRb;
			}
			while(tmpNode->left && (level++<128)){
				if(getRecordFromCache(start=tmpNode->left,buff)==0){
					delete buf;
					goto abortRb;
				}
			}
			if(level>=128){
				level=-1;
				break;
			}
		}else{
			while(level++<128){
				if(tmpNode->parent==0){
					if(buf->getSize() > (int)(incount*sizeof(int))){
						buf->setSize(incount*sizeof(int));
					}
					release();
					delete r;
					delete buff;
					return buf;
				}
				int node=start;
				if(getRecordFromCache(start=tmpNode->parent,buff)==0){
					delete buf;
					goto abortRb;
				}
				if(tmpNode->left == node){
					break;
				}
			}
			if(level>=128){
				level=-1;
				break;
			}
		}
		x[incount++]=start;
	}
	delete buff;
	if(level==-1){
		delete buf;
		RepairTableOnline();
		goto getRangeBUFFER;
	}
	if(incount>count)
		incount=count;
	if(buf->getSize()>(int)(incount*sizeof(int)))
		buf->setSize(incount*sizeof(int));
	release();
	delete r;
	return buf;
}

/*

Buffer* Table::getEqualsBuffer(char * val,Field *f,LinkedBuffer *fs,int order,Buffer** r,int recId)
{
	Buffer *eb=getEqualsBuffer(val,f,recId);
	if(fs && eb){
		if(*r==0){
			Field *f=getField(*fs);
			if(f && f->root){
				int sorder=order;
				if(fs->getType()=='d')
					sorder*=-1;
				lock();
				char *tmp=getRecordCached(f->root);
				if(tmp!=0){
					recordInfo* tmpNode=(recordInfo*)(tmp+f->offset);
					int total=tmpNode->leftWeight+tmpNode->rightWeight+tmpNode->centerWeight+1;
					*r=getRangeBuffer(0,0,f,0,total,order*sorder,fs->next);
				}
				release();
				if(*r && (sorder<0)){
					int *m=(int*)((char*)*(*r));
					int l=((*r)->getSize()/sizeof(int))-1;
					for(int i=0;i<l;++i){
						int t=m[i];
						m[i]=m[l];
						m[l--]=t;
					}
				}
			}
		}
		if(*r){
			int *m=(int*)((char*)*(*r));
			sortList(eb);
			int l=(*r)->getSize()/sizeof(int);
			int n=0;
			Buffer *ebuff=new Buffer(*eb,eb->getSize());
			int *p=(int*)((char*)*ebuff);
			for(int k=0;k<l;++k){
				if(m[k]!=0){
					if(findinList(eb,m[k])){
						p[n++]=m[k];
						m[k]=0;
					}
				}
			}
			ebuff->setSize(n*sizeof(int));
			delete eb;
			eb=ebuff;
		}
	}
	return eb;
}
*/


Buffer* Table::getEqualsBuffer(char * val,Field *f,LinkedBuffer *fs,int order,Buffer** r,int recId)
{
	Buffer *eb=getEqualsBuffer(val,f,recId);
	if(fs && eb){
		if(*r==0){
			Field *f=getField(*fs);
			if(f && f->root){
				int sorder=order;
				if(fs->getType()==1)
					sorder*=-1;
				lock();
				char *tmp=getRecordCached(f->root);
				if(tmp!=0){
					recordInfo* tmpNode=(recordInfo*)(tmp+f->offset);
					int total=tmpNode->leftWeight+tmpNode->rightWeight+tmpNode->centerWeight+1;
					*r=getRangeBuffer(0,0,f,0,total,order*sorder,fs->next);
				}
				release();
				if(*r && (sorder<0)){
					int *m=(int*)((char*)*(*r));
					int l=((*r)->getSize()/sizeof(int))-1;
					for(int i=0;i<l;++i){
						int t=m[i];
						m[i]=m[l];
						m[l--]=t;
					}
				}
			}
		}
		if(*r){
			int *m=(int*)((char*)*(*r));
			sortList(eb);
			int l=(*r)->getSize()/sizeof(int);
			int n=0;
			Buffer *ebuff=new Buffer(*eb,eb->getSize());
			int *p=(int*)((char*)*ebuff);
			for(int k=0;k<l;++k){
				if(m[k]!=0){
					if(findinList(eb,m[k])){
						p[n++]=m[k];
						m[k]=0;
					}
				}
			}
			ebuff->setSize(n*sizeof(int));
			delete eb;
			eb=ebuff;
		}
	}
	return eb;
}



Buffer* Table::getEqualsBuffer(char * val,Field *f,Buffer *fromlist)
{
	Buffer *z=getSelectionFromCache(f,EQU,val,0);
	if(z==0){
		if(fromlist){
			int recId=searchTree(val,f);
			if(recId!=0){
				Buffer *bf=new Buffer(getRecordSize());
				if(getRecordFromCache(recId,bf)){
					char* tmp=*bf;
					recordInfo* tmpNode=(recordInfo*)(tmp+f->offset);
					if(tmpNode->centerWeight>=0){
						int n=fromlist->getSize()/sizeof(int);
						if(tmpNode->centerWeight > n){
							int *m=(int*)((char*)*fromlist);
							int of=getFieldOffset(f);
							int k=0;
							for(int i=0;i<n;++i){
								if(getRecordFromCache(m[i],bf)){
									if(tmp  && (compare(val,tmp+of,f->type)==0)){
										if(k<i)
											m[k]=m[i];
										k++;
									}
								}
							}
							fromlist->setSize(k*sizeof(int));
							delete bf;
							return fromlist;
						}
					}
				}
				delete bf;
			}
		}
		return getEqualsBuffer(val,f);
	}
	return z;
}


Buffer* Table::getEqualsBuffer(char * val,Field *f,int recId)
{
	Buffer *z=getSelectionFromCache(f,EQU,val,0);
	if(z){
		return z;
	}
	lock();
	if(recId==0)
		recId=searchTree(val,f);
	if(recId==0){
		release();
		return 0;
	}
	Buffer *buff = new Buffer(getRecordSize());
	char* tmp=*buff;
	Buffer *tmb=0;
	if(getRecordFromCache(recId,buff)){
		recordInfo* tmpNode=(recordInfo*)(tmp+f->offset);
		if(tmpNode->centerWeight>=0){
			int j=tmpNode->centerWeight;
			tmb=new Buffer((j+1)*sizeof(int));
			int *x=(int*)((char*)*tmb);
			while(j>=0){
				x[j--]=recId;
				if(tmpNode->center==0)
					break;
				recId=tmpNode->center;
				if(getRecordFromCache(recId,buff) == 0){
					delete tmb;
					tmb=0;
					goto abortEb;
				}
//				tmpNode=(recordInfo*)(tmp+f->offset);
			}
			if(tmb->getSize()/sizeof(int) > MINCACHESIZE){
				Selection *z=new Selection(new Buffer(val,f->size*elementSize(f->type)),0,f,EQU);
				z->putStore(new Buffer(*tmb,tmb->getSize()));
				addSelection(z);
			}
		}
	}
	abortEb:
	delete buff;
	release();
	return tmb;
}




int Table::getLastEqual(int node,Field*f)
{
	if(node==0)
		return 0;
	lock();
getLastEQUAL:
	Buffer *buff=new Buffer(getRecordSize());
	char* tmp=*buff;
	if(getRecordFromCache(node,buff)==0){
		delete buff;
		release();
		return 0;
	}
	int fo=getFieldOffset(f);
	recordInfo* tmpNode=(recordInfo*)(tmp+f->offset);
	Buffer *list=0;
	int *x=0;
	int count=0;
	if(tmpNode->centerWeight>=MINCACHESIZE){
		int n=0;
		getSelectionFromCache(f,EQU,tmp+fo,0,&n);
		if(n){
			delete buff;
			release();
			return n;
		}
		count=tmpNode->centerWeight;
		list=new Buffer((count+1)*sizeof(int));
		x=(int*)((char*)*list);
		x[count]=node;
	}
	while(tmpNode->center){
		int parent=node;
		node=tmpNode->center;
		if(x && (count>0))
			x[--count]=node;
		if((getRecordFromCache(node,buff)==0) || (tmpNode->parent!=parent)){
			delete buff;
			delete list;
			RepairTableOnline();
			goto getLastEQUAL;
		}
	}
	delete buff;
	if(x){
		if(count==0){
			Selection *z=new Selection(new Buffer(tmp+fo,f->size*elementSize(f->type)),0,f,EQU);
			z->putStore(list);
			addSelection(z);
		}else{
			delete list;
		}
	}
	release();
	return node;
}



int Table::getRangeSize(char* from,char*to,char type,Field *f,int* fromRec, int* toRec)
{
	int root=f->root;
	if(root==0)
		return 0;
	if(from && to && (compare(from,to,f->type)==0)){
		return 0;
	}
	lock();
getRangeSIZE:
	char *tmp=getRecordCached(root);
	if(tmp==0){
		release();
		return 0;
	}
	int total=0;
	int includes=0;
	recordInfo* tmpNode=(recordInfo*)(tmp+f->offset);
	int fo=getFieldOffset(f);
	int level=0;
	if(from && to){
		while(tmp && (level++<128)){
			int df=compare(from,tmp+fo,f->type);
			int dt=compare(to,tmp+fo,f->type);
			if((dt<0) && (df<0))
				root=tmpNode->left;
			else
				if((dt>0) && (df>0))
					root=tmpNode->right;
				else
					break;
				if(root){
					tmp=mustGetRecordCached(root);
					tmpNode=(recordInfo*)(tmp+f->offset);
				}else{
					release();
					if(type&EXCLUDE)
						return(dbf->getTotal()-1);
					return 0;
				}
		}
	}
	if(level>=128){
		RepairTableOnline();
		goto getRangeSIZE;
	}
	level=0;
	total=tmpNode->leftWeight+tmpNode->rightWeight+tmpNode->centerWeight+1;
	if(from!=0){
		int lastr=root;
		int recl=root;
		while((level++<128) && tmp){
			int d;
			if((d=compare(from,tmp+fo,f->type))<0){
				lastr=recl;
				if(tmpNode->left==0)
					break;
				recl=tmpNode->left;
			}
			else
				if(d>0){
					total-=tmpNode->centerWeight+tmpNode->leftWeight+1;
					if(tmpNode->right==0)         
						break;
					recl=tmpNode->right;
				}else{
					total-=tmpNode->centerWeight+tmpNode->leftWeight+1;
					if(type&INCLUDE_FROM){
						includes+=tmpNode->centerWeight+1;
						lastr=recl;
					}else{
						if(tmpNode->right){
							tmp=mustGetRecordCached(lastr=tmpNode->right);
							tmpNode=(recordInfo*)(tmp+f->offset);
							while((level++<128) && tmpNode->left){
								tmp=mustGetRecordCached(lastr=tmpNode->left);
								tmpNode=(recordInfo*)(tmp+f->offset);
							}
						}
					}
					break;
				}
				tmp=mustGetRecordCached(recl);
				tmpNode = (recordInfo*)(tmp+f->offset);
		}
		*fromRec=lastr;
	}else{
		*fromRec=getMin(f);
	}
	if(level>=128){
		RepairTableOnline();
		goto getRangeSIZE;
	}
	level=0;
	*fromRec=getLastEqual(*fromRec,f);
	if(to!=0){
		tmp=mustGetRecordCached(root);
		tmpNode=(recordInfo*)(tmp+f->offset);
		int lastr=root;
		int recr=root;
		while((level++<128) && tmp){
			int d;
			if((d=compare(to,tmp+fo,f->type))<0){
				total-=tmpNode->centerWeight+tmpNode->rightWeight+1;
				if(tmpNode->left==0)
					break;
				recr=tmpNode->left;
			}else
				if(d>0){
					lastr=recr;
					if(tmpNode->right==0)
						break;
					recr=tmpNode->right;
				}else{
					total-=tmpNode->centerWeight+tmpNode->rightWeight+1;
					if(type&INCLUDE_TO){
						includes+=tmpNode->centerWeight+1;
						lastr=recr;
					}else{
						if(tmpNode->left){
							tmp=mustGetRecordCached(lastr=tmpNode->left);
							tmpNode=(recordInfo*)(tmp+f->offset);
							while((level++<128) && tmpNode->right){
								tmp=mustGetRecordCached(lastr=tmpNode->right);
								tmpNode=(recordInfo*)(tmp+f->offset);
							}
						}
					}
					break;
				}
				tmp=mustGetRecordCached(recr);
				tmpNode = (recordInfo*)(tmp+f->offset);
		}
		*toRec=lastr;
	}else{
		*toRec=getMax(f);
	}
	if(level>=128){
		RepairTableOnline();
		goto getRangeSIZE;
	}
	release();
	if(type&EXCLUDE){
		return ((dbf->getTotal()-1-total)+includes);
	}else{
		return (total+includes);
	}
}


int Table::getNextEqual(int recId,char* val,Field *f,int dir)
{
	if(recId==0){
		recId = searchTree(val,f);
		if(dir>0)
			return(getLastEqual(recId,f));
		else
			return recId;
	}
	lock();
	char* tmp=getRecordCached(recId);
	recId=0;
	if(tmp){
		recordInfo* tmpNode=(recordInfo*)(tmp+f->offset);
		if(dir>0){
			if(tmpNode->centerWeight==-1)
				recId=tmpNode->parent;
		}else{
			if(tmpNode->center)
				recId=tmpNode->center;
		}
	}
	release();
	return recId;
}




#define HEIGHT_CHANGE 1
#define HEIGHT_NOCHANGE 0
int Table::deleteNode(int recId,Field *f)
{
	if(f->type==FILE_TYPE || f->type==BIN_TYPE)
		return 0;
	if(f->root==0)
		return 0;
	int previousRoot=f->root;
	char *defunct=getRecordCached(recId);
	if(defunct==0)
		return -59;
	recordInfo* defunctNode=(recordInfo*)(defunct+f->offset);
	if(defunctNode->center){
		int similarNode=defunctNode->center;
		char* childRec=getRecordCached(similarNode);
		if(childRec==0)
			return -60;
		recordInfo* childNode=(recordInfo*)(childRec+f->offset);
		if(childNode->parent==recId){
			defunctNode->center=childNode->center;
			memcpy(childNode,defunctNode,sizeof(recordInfo));
			dbf->bufferedPut(childRec,similarNode);
		}else
			return -2;
		if(defunctNode->left){
			char* leftRec=getRecordCached(defunctNode->left);
			if(leftRec){
				recordInfo* leftNode=(recordInfo*)(leftRec+f->offset);
				if(leftNode->parent==recId){
					leftNode->parent=similarNode;
					dbf->bufferedPut(leftRec,defunctNode->left);
				}else
					return -3;
			}else
				return -4;
        }
		if(defunctNode->right){
			char* rightRec=getRecordCached(defunctNode->right);
			if(rightRec){
				recordInfo* rightNode=(recordInfo*)(rightRec+f->offset);
				if(rightNode->parent==recId){
					rightNode->parent=similarNode;
					dbf->bufferedPut(rightRec,defunctNode->right);
				}else
					return -5;
			}else
				return -6;
        }
		if(defunctNode->parent){
			char* parentRec=getRecordCached(defunctNode->parent);
			if(parentRec){
				dbf->bufferedPut(parentRec,defunctNode->parent);
				recordInfo* parentNode=(recordInfo*)(parentRec+f->offset);
				int rootId=0;
				char* rootRec=0;
				if(parentNode->center==recId){
					parentNode->center=similarNode;
					rootId = searchTree(childRec+getFieldOffset(f),f);
					rootRec=getRecordCached(rootId);
					if(rootRec==0)
						return -7;
					dbf->bufferedPut(rootRec,rootId);
				}else{
					rootId=similarNode;
					rootRec=childRec;
					if(parentNode->left==recId){
						parentNode->left=similarNode;
					}else{
						if(parentNode->right==recId){
							parentNode->right=similarNode;
						}else{
							return -8;
						}
					}
				}
				if(rootId!=0){
					recordInfo* rootNode=(recordInfo*)(rootRec+f->offset);
					rootNode->centerWeight--;
					while(rootNode->parent){
						int cp=rootId;
						rootId=rootNode->parent;
						rootRec=getRecordCached(rootId);
						if(rootRec){
							rootNode=(recordInfo*)(rootRec+f->offset);
							if(rootNode->right==cp)
								rootNode->rightWeight--;
							else{
								if(rootNode->left==cp)
									rootNode->leftWeight--;
								else
									return -9;
							}
							dbf->bufferedPut(rootRec,rootId);
						}else
							return -10;
					}
				}else
					return -11;	
			}else{
				return -12;
			}
		}else{
			if(f->root==recId){
				childNode->centerWeight--;
				f->root=similarNode;
			}else
				return -13;
		}
		return (f->root!=previousRoot);
	}
	char* recBuff=0;
	recordInfo* node=0;
	int currentNode=defunctNode->parent;
	int heightChange=0;
	int cv=0;
	int cr=0;
	if(defunctNode->left==0 && defunctNode->right==0){
		if(currentNode==0){
			if(f->root==recId){
				f->root=0;
				f->unodes=0;
			}
			return 1;
		}else{
			recBuff=getRecordCached(currentNode);
			if(recBuff){
				dbf->bufferedPut(recBuff,currentNode);
				node=(recordInfo*)(recBuff+f->offset);
				if(node->left==recId){
					node->left=0;
					node->leftWeight=0;
					heightChange=-1;
				}else
					if(node->right==recId){
						node->right=0;
						node->rightWeight=0;
						heightChange=1;
					}else{
						if(node->center==recId){
							node->center=0;
							int rootId;
							char *rootRec;
							if(node->centerWeight==1){
								rootId=currentNode;
								rootRec=recBuff;
							}else{
								rootId = searchTree(recBuff+getFieldOffset(f),f);
								rootRec=getRecordCached(rootId);
								if(rootRec){
									dbf->bufferedPut(rootRec,rootId);
								}else{
									return -14;
								}
							}
							if(rootId && rootRec){
									recordInfo* rootNode=(recordInfo*)(rootRec+f->offset);
									rootNode->centerWeight--;
									while(rootNode->parent){
										int cp=rootId;
										rootId=rootNode->parent;
										rootRec=getRecordCached(rootId);
										if(rootRec){
											rootNode=(recordInfo*)(rootRec+f->offset);
											if(rootNode->right==cp)
												rootNode->rightWeight--;
											else{
												if(rootNode->left==cp)
													rootNode->leftWeight--;
												else
													return -15;
											}
											dbf->bufferedPut(rootRec,rootId);
										}else{
											return -16;
										}
									}
							}else
								return -17;
							return 0;
						}else
							return -18;
					}
			}else
				return -19;
		}
	}else
		if(defunctNode->left==0||defunctNode->right==0){
			int childRecId=defunctNode->left+defunctNode->right;
			char* childRec=getRecordCached(childRecId);
			if(childRec){
				recordInfo* childNode=(recordInfo*)(childRec+f->offset);
				if(childNode->parent==recId){
					childNode->parent=currentNode;
					dbf->bufferedPut(childRec,childRecId);
				}else
					return -20;
			}else
				return -30;
			if(currentNode==0){
				if(f->root==recId){
					f->root=childRecId;
					f->unodes--;
					return 1;
				}
				return -31;
			}else{
				recBuff=getRecordCached(currentNode);
				if(recBuff){
					dbf->bufferedPut(recBuff,currentNode);
					node=(recordInfo*)(recBuff+f->offset);
					if(node->left==recId){
						node->left=childRecId;
						node->leftWeight--;
						heightChange=-1;
					}else
						if(node->right==recId){
							node->right=childRecId;
							node->rightWeight--;
							heightChange=1;
						}else
							return -32;
				}else
					return -33;
			}
		}else{
			int childRecId  = defunctNode->right;
			char* childRec = getRecordCached(childRecId);
			if(childRec==0)
				return -34;
			recordInfo* childNode = (recordInfo*)(childRec + f->offset);
			while(childNode->left){
				childRecId=childNode->left;
				childRec=getRecordCached(childRecId);
				if(childRec==0)
					return -35;
				childNode=(recordInfo*)(childRec+f->offset);
			}
			dbf->bufferedPut(childRec,childRecId);
			if(currentNode==0){
				if(f->root==recId)
					f->root=childRecId;
				else
					return -36;
			}else{
				recBuff=getRecordCached(currentNode);
				if(recBuff==0)
					return -37;
				dbf->bufferedPut(recBuff,currentNode);
				node=(recordInfo*)(recBuff+f->offset);
				if(node->left==recId)
					node->left=childRecId;
				else{
					if(node->right==recId)
						node->right=childRecId;
					else
						return -38;

				}
			}
			char *gc=getRecordCached(defunctNode->left);
			if(gc==0)
				return -39;
			recordInfo* gcNode=(recordInfo*)(gc+f->offset);
			gcNode->parent=childRecId;
			dbf->bufferedPut(gc,defunctNode->left);
			int grandChild=childNode->right;
			if(childNode->parent!=recId){
				currentNode=childNode->parent;
				if((recBuff=getRecordCached(currentNode))==0)
					return -40;
				dbf->bufferedPut(recBuff,currentNode);
				node=(recordInfo*)(recBuff+f->offset);
				if(node->left==childRecId){
					node->left=grandChild;
					node->leftWeight-=childNode->centerWeight+1;
					heightChange=-1;
				}else
					return -42;
				if((gc=getRecordCached(defunctNode->right))==0)
					return -43;
				gcNode=(recordInfo*)(gc+f->offset);
				gcNode->parent=childRecId;
				dbf->bufferedPut(gc,defunctNode->right);
				if(grandChild){
					if((gc=getRecordCached(grandChild))==0)
						return -44;
					gcNode=(recordInfo*)(gc+f->offset);
					gcNode->parent=currentNode;
					dbf->bufferedPut(gc,grandChild);
				}
			}else{
				if(defunctNode->right==childRecId){
					defunctNode->right=grandChild;
					defunctNode->rightWeight--;
					currentNode=childRecId;
					recBuff=childRec;
					node=childNode;
					heightChange=1;
				}
			}
			defunctNode->rightWeight-=childNode->centerWeight;
			defunctNode->center=childNode->center;
			defunctNode->centerWeight=childNode->centerWeight;
			memcpy(childNode,defunctNode,sizeof(recordInfo));
			cr=childRecId;
			cv=childNode->centerWeight;
		}
		{
			cv++;
			char* rootRec=recBuff;
			recordInfo* rootNode=node;
			int rootId=currentNode;
			if(rootId==cr)
				cv=1;
			while(rootNode->parent){
				int cp=rootId;
				rootId=rootNode->parent;
				if(rootId==cr)
					cv=1;
				rootRec=getRecordCached(rootId);
				if(rootRec){
					rootNode=(recordInfo*)(rootRec+f->offset);
					if(rootNode->right==cp)
						rootNode->rightWeight-=cv;
					else
						if(rootNode->left==cp)
							rootNode->leftWeight-=cv;
						else
							return -45;
						dbf->bufferedPut(rootRec,rootId);
				}else
					return -46;
			}
		}
		f->unodes--;
		while(heightChange){
			int child=currentNode;
			node->balance-=heightChange;
			if(node->balance==0)
				heightChange=HEIGHT_CHANGE;
			else{
				heightChange=HEIGHT_NOCHANGE;
				if(node->balance < -1){
					char *tmp=getRecordCached(node->left);
					if(tmp==0)
						return -47;
					int current=node->left;
					dbf->bufferedPut(tmp,current);
					recordInfo* childNode=(recordInfo*)(tmp+f->offset);
					if(childNode->balance == 1){
						char *rootBuff=getRecordCached(childNode->right);
						if(rootBuff==0)
							return -48;
						dbf->bufferedPut(rootBuff,childNode->right);
						recordInfo* rootNode=(recordInfo*)(rootBuff+f->offset);
						childNode->parent=childNode->right;
						rootNode->parent=node->parent;
						node->parent=childNode->parent;
						node->left=rootNode->right;
						rootNode->right=currentNode;
						childNode->right=rootNode->left;
						rootNode->left=current;
						if(rootNode->balance>0){
							childNode->balance=-1*rootNode->balance;
						}else{
							childNode->balance=0;
						}
						if(rootNode->balance<0){
							node->balance=-1*rootNode->balance;
						}else{
							node->balance=0;
						}
						rootNode->balance=0;
						if(childNode->right!=0){
							char *gc=getRecordCached(childNode->right);
							if(gc==0)
								return -49;
							recordInfo* gcNode=(recordInfo*)(gc+f->offset);
							gcNode->parent=rootNode->left;
							dbf->bufferedPut(gc,childNode->right);
							childNode->rightWeight=gcNode->leftWeight+gcNode->rightWeight+gcNode->centerWeight+1;
						}else
							childNode->rightWeight=0;
						if(node->left){
							char* gc=getRecordCached(node->left);
							if(gc==0)
								return -50;
							recordInfo* gcNode=(recordInfo*)(gc+f->offset);
							gcNode->parent=rootNode->right;
							dbf->bufferedPut(gc,node->left);
							node->leftWeight=gcNode->leftWeight+gcNode->rightWeight+gcNode->centerWeight+1;
						}else
							node->leftWeight=0;
						rootNode->leftWeight=childNode->rightWeight+childNode->leftWeight+childNode->centerWeight+1;
						rootNode->rightWeight=node->rightWeight+node->leftWeight+node->centerWeight+1;
						currentNode=node->parent;
						node=rootNode;
						heightChange=HEIGHT_CHANGE;
					}else{
						if(childNode->balance){
							heightChange=HEIGHT_CHANGE;
						}else{
							heightChange=HEIGHT_NOCHANGE;
						}
						node->balance=-(++childNode->balance);
						childNode->parent=node->parent;
						node->parent=current;
						node->left=childNode->right;
						childNode->right=currentNode;
						if(node->left){
							char *gc=getRecordCached(node->left);
							if(gc==0)
								return -51;
							recordInfo* gcNode=(recordInfo*)(gc+f->offset);
							gcNode->parent=currentNode;
							dbf->bufferedPut(gc,node->left);
							node->leftWeight=gcNode->leftWeight+gcNode->rightWeight+gcNode->centerWeight+1;
						}else
							node->leftWeight=0;
						childNode->rightWeight=node->leftWeight+node->rightWeight+node->centerWeight+1;
						currentNode=current;
						node=childNode;
					}
				}else{
					if(node->balance > 1){
						char *tmp=getRecordCached(node->right);
						if(tmp==0)
							return -52;
						int current=node->right;
						dbf->bufferedPut(tmp,current);
						recordInfo* childNode=(recordInfo*)(tmp+f->offset);
						if(childNode->balance == -1){
							char *rootBuff=getRecordCached(childNode->left);
							if(rootBuff==0)
								return -53;
							dbf->bufferedPut(rootBuff,childNode->left);
							recordInfo* rootNode=(recordInfo*)(rootBuff+f->offset);
							childNode->parent=childNode->left;
							rootNode->parent=node->parent;
							node->parent=childNode->parent;
							node->right=rootNode->left;
							rootNode->left=currentNode;
							childNode->left=rootNode->right;
							rootNode->right=current;
							if(rootNode->balance>0){
								node->balance=-1*rootNode->balance;
							}else{
								node->balance=0;
							}
							if(rootNode->balance<0){
								childNode->balance=-1*rootNode->balance;
							}else{
								childNode->balance=0;
							}
							rootNode->balance=0;
							if(childNode->left){
								char *gc=getRecordCached(childNode->left);
								if(gc==0)
									return -54;
								recordInfo* gcNode=(recordInfo*)(gc+f->offset);
								gcNode->parent=rootNode->right;
								dbf->bufferedPut(gc,childNode->left);
								childNode->leftWeight=gcNode->leftWeight+gcNode->rightWeight+gcNode->centerWeight+1;
							}else
								childNode->leftWeight=0;
							if(node->right){
								char* gc=getRecordCached(node->right);
								if(gc==0)
									return -55;
								recordInfo* gcNode=(recordInfo*)(gc+f->offset);
								gcNode->parent=currentNode;
								dbf->bufferedPut(gc,node->right);
								node->rightWeight=gcNode->leftWeight+gcNode->rightWeight+gcNode->centerWeight+1;
							}else
								node->rightWeight=0;
							rootNode->rightWeight=childNode->rightWeight+childNode->leftWeight+childNode->centerWeight+1;
							rootNode->leftWeight=node->rightWeight+node->leftWeight+node->centerWeight+1;
							currentNode=node->parent;
							node=rootNode;
							heightChange=HEIGHT_CHANGE;
						}else{
							if(childNode->balance){
								heightChange=HEIGHT_CHANGE;
							}else{
								heightChange=HEIGHT_NOCHANGE;
							}
							node->balance=-(--childNode->balance);
							childNode->parent=node->parent;
							node->parent=current;
							node->right=childNode->left;
							childNode->left=currentNode;
							if(node->right){
								char *gc=getRecordCached(node->right);
								if(gc==0)
									return -56;
								recordInfo* gcNode=(recordInfo*)(gc+f->offset);
								gcNode->parent=currentNode;
								dbf->bufferedPut(gc,node->right);
								node->rightWeight=gcNode->leftWeight+gcNode->rightWeight+gcNode->centerWeight+1;
							}else
								node->rightWeight=0;
							childNode->leftWeight=node->leftWeight+node->rightWeight+node->centerWeight+1;
							currentNode=current;
							node=childNode;
						}
					}
				}
			}
			if(node->parent==0){
				f->root=currentNode;
				break;
			}
			int currentRoot=currentNode;
			currentNode=node->parent;
			recBuff=getRecordCached(currentNode);
			if(recBuff==0)
				return -57;
			dbf->bufferedPut(recBuff,currentNode);
			node=(recordInfo*)(recBuff+f->offset);
			if(node->left==child){
				node->left=currentRoot;
				heightChange*=-1;
			}else{
				if(node->right==child)
					node->right=currentRoot;
				else
					return -58;
			}
		}
		return 1;
}




int Table::insertNode(int newRecord,Field *f,int pos) // returns 1 if root is changed;else 0
{
	if(f->type==FILE_TYPE || f->type==BIN_TYPE)
		return 0;
	char *newRec=getRecordCached(newRecord);
	if(newRec==0)
		return -61;
	recordInfo* newnode=(recordInfo*)(newRec+f->offset);
	memset(newnode,0,sizeof(recordInfo));
	if(f->root==0){
		dbf->bufferedPut(newRec,newRecord);
		f->root=newRecord;
		f->unodes=1;
		return 1;
    }
	int recId=f->root;
	int fo=getFieldOffset(f);
	char *val=newRec+fo;
	int result=0;
	recordInfo *node=0;
	char* recBuff=0;
	int currentNode=0;
	while(recId!=0){
		currentNode=recId;
		recBuff=getRecordCached(recId);
		if(recBuff==0)
			return -62;
		dbf->bufferedPut(recBuff,recId);
		node = (recordInfo*)(recBuff+f->offset);
		if((result=compare(val,recBuff+fo,f->type))<0){
			node->leftWeight++;
			recId=node->left;
		}
		else
			if(result>0){
				node->rightWeight++;
				recId=node->right;
			}
			else{
				node->centerWeight++;
				if(pos!=0){
					int srec=recId;
					while(recId!=pos){
						if(node->center==0){
							recId=srec;
							recBuff=getRecordCached(recId);
							if(recBuff==0)
								return -63;
							node=(recordInfo*)(recBuff+f->offset);
							pos=0;
							break;
						}
						recId=node->center;
						recBuff=getRecordCached(recId);
						if(recBuff==0)
							return -64;
						node=(recordInfo*)(recBuff+f->offset);
						
					}
				}
				if(pos==0){
					while(recId>newRecord){
						if(node->center==0){
							newnode->centerWeight=-1;
							node->center=newRecord;
							dbf->bufferedPut(recBuff,recId);
							newnode->parent=recId;
							return 0;
						}
						recId=node->center;
						recBuff=getRecordCached(recId);
						if(recBuff==0)
							return -65;
						node=(recordInfo*)(recBuff+f->offset);
					}
				}
				int update=0;
				memcpy(newnode,node,sizeof(recordInfo));
				newnode->center=recId;
				if(newnode->parent){
					char *tmp=getRecordCached(newnode->parent);
					if(tmp==0)
						return -66;
					dbf->bufferedPut(tmp,newnode->parent);
					recordInfo* tmpnode=(recordInfo*)(tmp+f->offset);
					if(tmpnode->left==recId)
						tmpnode->left=newRecord;
					else
						if(tmpnode->right==recId)
							tmpnode->right=newRecord;
						else
							if(tmpnode->center==recId)
								tmpnode->center=newRecord;
							else
								return -67;
				}else{
					f->root=newRecord;
					update=1;
				}
				if(newnode->left){
					char *tmp=getRecordCached(newnode->left);
					if(tmp==0)
						return -68;
					recordInfo* tmpnode=(recordInfo*)(tmp+f->offset);
					tmpnode->parent=newRecord;
					dbf->bufferedPut(tmp,newnode->left);
				}
				if(newnode->right){
					char *tmp=getRecordCached(newnode->right);
					if(tmp==0)
						return -69;
					recordInfo* tmpnode=(recordInfo*)(tmp+f->offset);
					tmpnode->parent=newRecord;
					dbf->bufferedPut(tmp,newnode->right);
				}
				node->parent=newRecord;
				node->left=node->right=0;
				node->centerWeight=-1;
				node->leftWeight=node->rightWeight=0;
				dbf->bufferedPut(recBuff,recId);
				return update;
			}
    }
    f->unodes++;
    newnode->parent=currentNode;
    if(result>0){
		node->right=newRecord;
		node->balance+=HEIGHT_CHANGE;
	}
    else{
		node->left=newRecord;
		node->balance-=HEIGHT_CHANGE;
	}
    if(node->balance==0)
		return 1;
    int heightChange=HEIGHT_CHANGE;
    int child=currentNode;
    while(node->parent!=0){
		int currentRoot=currentNode;
		currentNode=node->parent;
		recBuff=getRecordCached(currentNode);
		if(recBuff==0)
			return -70;
		dbf->bufferedPut(recBuff,currentNode);
		node=(recordInfo*)(recBuff+f->offset);
		if(heightChange || (child!=currentRoot)){
			if(node->left==child){
				node->left=currentRoot;
				node->balance-=heightChange;
			}
			else{
				node->right=currentRoot;
				node->balance+=heightChange;
			}
		}
		if(heightChange==0 || node->balance==0)
			return 1;
		heightChange=0;
		child=currentNode;
		if(node->balance < -1){
			char *tmp=getRecordCached(node->left);
			if(tmp==0)
				return -71;
			int current=node->left;
			dbf->bufferedPut(tmp,current);
			recordInfo* childNode=(recordInfo*)(tmp+f->offset);
			if(childNode->balance == 1){
				char *rootBuff=getRecordCached(childNode->right);
				if(rootBuff==0)
					return -72;
				dbf->bufferedPut(rootBuff,childNode->right);
				recordInfo* rootNode=(recordInfo*)(rootBuff+f->offset);
				childNode->parent=childNode->right;
				rootNode->parent=node->parent;
				node->parent=childNode->parent;
				node->left=rootNode->right;
				rootNode->right=currentNode;
				childNode->right=rootNode->left;
				rootNode->left=current;
				if(rootNode->balance>0){
					childNode->balance=-1*rootNode->balance;
				}else{
					childNode->balance=0;
				}
				if(rootNode->balance<0){
					node->balance=-1*rootNode->balance;
				}else{
					node->balance=0;
				}
				rootNode->balance=0;
				if(childNode->right!=0){
					char *gc=getRecordCached(childNode->right);
					if(gc==0)
						return -73;
					recordInfo* gcNode=(recordInfo*)(gc+f->offset);
					gcNode->parent=rootNode->left;
					dbf->bufferedPut(gc,childNode->right);
					childNode->rightWeight=gcNode->leftWeight+gcNode->rightWeight+gcNode->centerWeight+1;
				}else
					childNode->rightWeight=0;
				if(node->left){
					char* gc=getRecordCached(node->left);
					if(gc==0)
						return -74;
					recordInfo* gcNode=(recordInfo*)(gc+f->offset);
					gcNode->parent=rootNode->right;
					dbf->bufferedPut(gc,node->left);
					node->leftWeight=gcNode->leftWeight+gcNode->rightWeight+gcNode->centerWeight+1;
				}else
					node->leftWeight=0;
				rootNode->leftWeight=childNode->rightWeight+childNode->leftWeight+childNode->centerWeight+1;
				rootNode->rightWeight=node->rightWeight+node->leftWeight+node->centerWeight+1;
				recBuff=rootBuff;
				currentNode=node->parent;
				node=rootNode;
				heightChange=HEIGHT_CHANGE;
			}else{
				if(childNode->balance){
					heightChange=HEIGHT_CHANGE;
				}else{
					heightChange=HEIGHT_NOCHANGE;
				}
				node->balance=-(++childNode->balance);
				childNode->parent=node->parent;
				node->parent=current;
				node->left=childNode->right;
				childNode->right=currentNode;
				if(node->left){
					char *gc=getRecordCached(node->left);
					if(gc==0)
						return -75;
					recordInfo* gcNode=(recordInfo*)(gc+f->offset);
					gcNode->parent=currentNode;
					dbf->bufferedPut(gc,node->left);
					node->leftWeight=gcNode->leftWeight+gcNode->rightWeight+gcNode->centerWeight+1;
				}else
					node->leftWeight=0;
				childNode->rightWeight=node->leftWeight+node->rightWeight+node->centerWeight+1;
				currentNode=current;
				recBuff=tmp;
				node=childNode;
			}
		}else{
			if(node->balance > 1){
				char *tmp=getRecordCached(node->right);
				if(tmp==0)
					return -80;
				int current=node->right;
				dbf->bufferedPut(tmp,current);
				recordInfo* childNode=(recordInfo*)(tmp+f->offset);
				if(childNode->balance == -1){
					char *rootBuff=getRecordCached(childNode->left);
					if(rootBuff==0)
						return -76;
					dbf->bufferedPut(rootBuff,childNode->left);
					recordInfo* rootNode=(recordInfo*)(rootBuff+f->offset);
					childNode->parent=childNode->left;
					rootNode->parent=node->parent;
					node->parent=childNode->parent;
					node->right=rootNode->left;
					rootNode->left=currentNode;
					childNode->left=rootNode->right;
					rootNode->right=current;
					if(rootNode->balance>0){
						node->balance=-1*rootNode->balance;
					}else{
						node->balance=0;
					}
					if(rootNode->balance<0){
						childNode->balance=-1*rootNode->balance;
					}else{
						childNode->balance=0;
					}
					rootNode->balance=0;
					if(childNode->left){
						char *gc=getRecordCached(childNode->left);
						if(gc==0)
							return -77;
						recordInfo* gcNode=(recordInfo*)(gc+f->offset);
						gcNode->parent=rootNode->right;
						dbf->bufferedPut(gc,childNode->left);
						childNode->leftWeight=gcNode->leftWeight+gcNode->rightWeight+gcNode->centerWeight+1;
					}else
						childNode->leftWeight=0;
					if(node->right){
						char* gc=getRecordCached(node->right);
						if(gc==0)
							return -78;
						recordInfo* gcNode=(recordInfo*)(gc+f->offset);
						gcNode->parent=currentNode;
						dbf->bufferedPut(gc,node->right);
						node->rightWeight=gcNode->leftWeight+gcNode->rightWeight+gcNode->centerWeight+1;
					}else
						node->rightWeight=0;
					rootNode->rightWeight=childNode->rightWeight+childNode->leftWeight+childNode->centerWeight+1;
					rootNode->leftWeight=node->rightWeight+node->leftWeight+node->centerWeight+1;
					recBuff=rootBuff;
					currentNode=node->parent;
					node=rootNode;
					heightChange=HEIGHT_CHANGE;
				}else{
					if(childNode->balance){
						heightChange=HEIGHT_CHANGE;
					}else{
						heightChange=HEIGHT_NOCHANGE;
					}
					node->balance=-(--childNode->balance);
					childNode->parent=node->parent;
					node->parent=current;
					node->right=childNode->left;
					childNode->left=currentNode;
					if(node->right){
						char *gc=getRecordCached(node->right);
						if(gc==0)
							return -79;
						recordInfo* gcNode=(recordInfo*)(gc+f->offset);
						gcNode->parent=currentNode;
						dbf->bufferedPut(gc,node->right);
						node->rightWeight=gcNode->leftWeight+gcNode->rightWeight+gcNode->centerWeight+1;
					}else
						node->rightWeight=0;
					childNode->leftWeight=node->leftWeight+node->rightWeight+node->centerWeight+1;
					currentNode=current;
					recBuff=tmp;
					node=childNode;
				}
			}
		}
		heightChange=1-heightChange;
    }
	if(currentNode!=f->root)
		f->root=currentNode;
	return 1;
}



char* Table::getFileName(FILEINFO* f)
{ 
	if(fileInfoSize==sizeof(FILEINFO))
		return f->filename;
	return 0;
}


void Table::putFileName(FILEINFO* f,File *inf)
{ 
	if(fileInfoSize==sizeof(FILEINFO)){
		char* fileName=inf->getRealName();
		strncpy(f->filename,fileName,63);
		f->filename[63]=0;
	}
	strncpy(f->extention,inf->getExt(),7);
	f->extention[7]=0;
}


int Table::textField(char* fldname)
{
	Field* f=getField(fldname);
	if(f!=0){
			if(((f->flags&BINARY_DATA)==0) &&
				((f->type==CHAR_TYPE) || (f->type==FILE_TYPE))){
				return 1;
			}
	}
	return 0;
}

void sendFile(RealFile *fd,char *borderline);

void Table::addChild(htmlBuffer* tablename)
{
	if(childs==0)
		childs=tablename;
	else{
		htmlBuffer* tmp=childs;
		while(tmp->next){
			if(stricmp(*tablename,*tmp)==0)
				return;
			tmp=tmp->next;
		}
		tmp->next=tablename;
	}
}


void Table::removeChild(char* tablename)
{
	if(childs!=0){
		htmlBuffer* prev=0;
		for(htmlBuffer* tmp=childs;tmp!=0;tmp=tmp->next){
			if(stricmp(tablename,*tmp)==0){
				if(prev)
					prev->next=tmp->next;
				else
					childs=tmp->next;
				delete tmp;
				break;
			}
			prev=tmp;
		}
	}
}



VLINK* vhead=0;
VLINK* vtail=0;
VLINK* vlast=0;
int vn=0;

mutex* Vlock=0;

void initVlock()
{
	Vlock=new mutex();
}



#define CACHEMIN 512


static int cacheMax;


void setCacheSize(int n)
{
	if (n>1024)
		n=1024;
	if(n<64)
		n=64;
	cacheMax=n*1024*1024;
}


/*

static int cacheMax;
#define MAXCACHE ((ULONG)(cacheMax/3)*2)

static int cacheSpace=-1;

void setCacheSize(int n)
{
	int dif=n*1024*1024-cacheMax;
	if(dif>0){
		cacheSpace+=dif;
		cacheMax=n*1024*1024;
	}
}
*/


Table::Table(TableFile *fl)
 : URLhandler(" "),fields(0),headerSize(0),maxRecords(-1),defaultCache(0),recordSize(0),dbf(fl),name(0),childs(0),wt(0),locked(-1),dbl(0)
{
	needsRepair=0;
	SField *sf;
	char *b=dbf->getHeader();
	if(b==0){
		exitTableError(202,"Cannot read table header");
	}
	char *hb=b;
	int *nf = (int*) b;
	Field *f;
	int offset = 0;
	fields = 0;
	if((*nf>0) && (*nf < MAXFIELDS)){
		b+=sizeof(int);
		maxRecords=*((int*)b);
		b+=sizeof(int);
		for(int i=0;i<*nf;++i){   
			sf = new SField();
			f=*sf;
			memcpy((char*) f,b,FIELDSIZE);
			f->hdOffset=b-hb;
			b+=FIELDSIZE;
			f->next = fields;
			f->offset = offset+sizeof(char);
			offset += getFieldSize(f);
			fields = sf;
		}
	}
}



Table::Table(char* s)
  :URLhandler(" "),fields(0),headerSize(0),maxRecords(-1),defaultCache(0),recordSize(0),dbf(0),name(0),childs(0),wt(0),locked(-1),dbl(new mutex())
{
	fileInfoSize=sizeof(FILEINFO);
	tableName[0]=0;
	dbname[0]=0;
	//char *s = *tname;
	name = new Buffer(s,strlen(s)+1);
	int i;
	for(i = strlen(s)-1;(i>0) && (s[i]!='.');--i);
	if(i==0)
		return;
	int j=i;
	for(;(i > 0) && (s[i]!=FSLASH);--i);
	if(i==0)
		return;
	else{
		for(int k=i-1;k!=0;k--)
			if(s[k]==FSLASH){
				k++;
				strncpy(dbname,s+k,i-k);
				dbname[i-k]=0;
				for(k=0;dbname[k];k++)
					if(dbname[k]=='.'){
						dbname[k]=0;
						break;
					}
					break;
			}
			i++;
    }
	caches=new CacheList(CACHEMIN);
	strncpy(tableName,s+i,j-i);
	tableName[j-i]=0;
	memset(cachedSelection,0,sizeof(cachedSelection));
	initTable();
}

/*
Table::Table(char* db,char* tname)
 : URLhandler(" "),fields(0),headerSize(0),maxRecords(-1),defaultCache(0),recordSize(0),dbf(0),name(0),path(0),childs(0),wt(0),locked(-1),dbl(new mutex())
{
	fileInfoSize=sizeof(FILEINFO);
	int n;
	tableName[0]=0;
	dbname[0]=0;
	for(n=strlen(db)-1;n>0;--n){
		if(db[n]==FSLASH){
			n++;
			break;
		}
	}
	int j=0;
	for(;(dbname[j]=db[n])!=0;++n,++j){
		if(db[n]=='.')
			break;
	}
	dbname[j]=0;
	caches=new CacheList(CACHEMIN);
	name = new Buffer(n=(strlen(tname)+strlen(db)+8));
	snprintf(*name,n,"%s%c%s.data",db,FSLASH,tname);
	strcpy(tableName,tname);
	memset(cachedSelection,0,sizeof(cachedSelection));
	initTable();
}
*/

void Table::initTable()
{
	needsRepair=0;
	for(int i=0;i<MAXSELECTION;++i){
		delete cachedSelection[i];
		cachedSelection[i]=0;
	}
	clearCache();
	caches->init();
	if(exists() && (dbf==0)){
		dbf = findOpenTable(*name);
		if(dbf==0)
			dbf = new TableFile(*name,dbl);
		else
			dbf->setLockable(dbl);
		lock();
		getTableDef();
		if(repair==0){
			if(dbf->needRepair())
				RepairTable(1);
		}
		release();
	}
	if(exists()){
		getTableInfo(1);
	}
}



Table::~Table()
{
	if(name){
		delete name; 
		delete dbf;
		clearCache();
		for(int i=0;i<MAXSELECTION;++i)
			delete cachedSelection[i];
		delete defaultCache;
	}
	cleanupFieldList();
	delete dbl;
	deleteHtmlBuffer(childs);
}



Field* Table::getField(char* fieldname)
{
	for( SField *sf=fields;sf!=0; sf = (SField *)(((Field *)*sf) ->next)){
		if(stricmp(fieldname,((Field *)*sf)->fieldName)==0)
			return(*sf);
	}
	return(0);
}

void Table::output(genericObject* objs,Runnable* thread,File *of)
{
genericObject *form=getObject("form",objs);
Buffer *tmpbuff = new Buffer(4500);
char *dbname=*tmpbuff;
char *scratchpad=dbname+256;
if(form){
 strcpy(dbname,form->showValue("db"));
 int i;
 for(i=strlen(dbname)-1;i>0 && dbname[i]!='.';--i);
 if(dbname[i]=='.')
  dbname[i]=0;
 char *command=form->showValue("command");
 if(command && *command){
   if(stricmp(command,"modify")==0){
      char *action=form->showValue("action");
      if(action==0 || stricmp(action,"cancel")==0){
         goto info;
         }else
      if(stricmp(action,"modify")==0){
         char* fname=form->showValue("selected");
         if(fname==0)
            goto info;
         Field *f=getField(fname);
         if(f==0)
            goto info;
         fname=form->showValue("type");
         if(fname==0)
            goto info;
         if(f->type==CHAR_TYPE || f->type==FILE_TYPE){
            if(stricmp(fname,"string") && stricmp(fname,"image") && stricmp(fname,"RealNumber") && stricmp(fname,"text") && stricmp(fname,"numeric"))
               goto info;
            }else
         if(f->type==INT_TYPE || f->type==REAL_TYPE){
            if(stricmp(fname,"String") && stricmp(fname,"Numeric") && stricmp(fname,"realNumber") && strncmp(fname,"Relation->",10))
               goto info;
            }else
         if(f->type==TIME_TYPE){
            if(stricmp(fname,"Time") && stricmp(fname,"Numeric"))
               goto info;
            }
         fname=form->showValue("fieldname");
         if(fname==0)
            goto info;
         fname=form->showValue("size");
         if(fname==0 || atoi(fname)<=0)
            goto info;
         if(atoi(fname)>1 && stricmp(form->showValue("type"),"string")){
			 strcpy(fname,"1");
            }
         lock();
         modifyField(form,f);
         release();
         goto info;
         }else
      if(stricmp(action,"add")==0){
         char* fname=form->showValue("type");
         if(fname==0)
            goto info;
         fname=form->showValue("fieldname");
         if(fname==0){
            of->write("<h1>Nothing To Do!</h1>");
            goto info;
		 }
         Field* f=getField(fname);
         if(f!=0){
            of->write("<h1>Field Exists</h1>");
            goto info;
          }
         fname=form->showValue("selected");
         if(fname!=0)
           f=getField(fname);
         fname=form->showValue("size");
         if(fname==0 || atoi(fname)<=0){
			             of->write("<h1>Field Size must be positive</h1>");
            goto info;
		 }
         if(atoi(fname)>1 && stricmp(form->showValue("type"),"string")){
            of->write("<h1>Invalid Value for Size</h1>");
            goto info;
            }
         lock();
         addField(form,f);
         release();
         goto info;
         }else
      if(stricmp(action,"Repair")==0){
         lock();
         RepairTableOnline();
         release();
         goto info;
         }else
      if(stricmp(action,"backup")==0){
         lock();
		 backupTable();
         release();
         goto info;
         }else
			 if(stricmp(action,"delete")==0){
				 char* fname=form->showValue("selected");
				 if(fname==0)
					 goto info;
				 Field *f=getField(fname);
				 if(f==0)
					 goto info;
				 lock();
				 deleteField(f);
				 release();
				 goto info;
			 }else
		      if(stricmp(action,"modify field")==0){
				  if(form->showValue("field")){
					  Field *f=getField(form->showValue("field"));
					  if(f==0)
						  goto info;
					  snprintf(scratchpad,1024,"<a href=\"dbms.html?db=%s&table=%s&command=tableinfo\">Modifying <font color=eecc66>%s.%s</a><br>",dbname,tableName,dbname,tableName);
					  of->write(scratchpad);
					  of->write("<font size=4 color = ee3366>Modify Selected Field : <font color=ffffff>");
					  snprintf(scratchpad,1024,"%s (Type=%s  size=%d*%d %s)",f->fieldName,translateType(f),f->size,f->dim,flagList(f->flags));
					  of->write(scratchpad);
					  of->write("</font>");
					  of->write("<form method=post action=dbms.html enctype=multipart/form-data>");
					  of->write("<input type=hidden name=command value=modify><input type=hidden name=selected value=\"");
					  of->write(f->fieldName);
					  of->write("\"><input type=hidden name=db value=");
					  of->write(dbname);
					  of->write("><input type=hidden name=table value=");
					  of->write(tableName);
					  of->write("><table bgcolor=ee3366 cellpadding=4 cellspacing=4><tr><td>");
					  if(f->type==CHAR_TYPE || f->type==FILE_TYPE)
						  of->write("<table bgcolor=cc3399 cellspacing=0><tr><td><font color=eeee33><b>Field Name</td><td><font color=eeee33><b>Type</td><td><font color=eeee33><b>Size</td><td><font color=eeee33><b>Dimension</td><td><font color=eeee33><b>Flags</td><td><font color=eeee33><b>Default Value</td><tr>");
					  else
						  of->write("<table bgcolor=cc3399 cellspacing=0><tr><td><font color=eeee33><b>Field Name</td><td><font color=eeee33><b>Type</td><td><font color=eeee33><b>Dimension</td><td><font color=eeee33><b>Flags</td><td><b><font color=eeee33>Default Value</td><tr>");
					  of->write("<td><input type=text name=fieldname value=\"");
					  of->write(f->fieldName);
					  of->write("\"></td>");
					  if(f->type==CHAR_TYPE || f->type==FILE_TYPE){
						  if(f->type==CHAR_TYPE)
							  of->write("<td><select name=type><option>String</option><Option>Numeric</option><option>RealNumber</option><option>Text</option><option>Image</option></select></td>");
						  else{
							  of->write("<td><select name=type>");
							  if(f->flags&BINARY_DATA)
							   of->write("<option>Image<option>Text<Option>String</select></td>");
							  else
							   of->write("<option>Text<option>Image<Option>String</select></td>");
						  }
						  snprintf(scratchpad,1024,"%d",f->size);
						  of->write("<td><input type=text name=size value=\"");
						  of->write(scratchpad);
						  of->write("\" size=4></td>");
					  }else{
						  of->write("<input type=hidden name=size value=1>");
						  if(f->type==INDEX_TYPE){
							  of->write("<td><select name=type><option>Relation->");
							  of->write(f->tableName);
							  of->write("</option><option>Numeric</option></select></td>");
						  }
						  else
							  if(f->type==INT_TYPE || f->type==REAL_TYPE){
								  of->write("<td><select name=type><option>Numeric</option><Option>String</option><Option>RealNumber</option><option>- - - - - - - - -</option>");
								  htmlBuffer *rtables=getTables(dbname);
								  if(rtables){
									  of->write("<OPTION>- - - - - - - - -\r\n");
									  for(htmlBuffer* ltables=rtables;ltables!=0;ltables=ltables->next){
										  if(stricmp(*ltables,tableName)){
											  snprintf(scratchpad,128,"<OPTION>Relation->%s\r\n",(char*)*ltables);
											  of->write(scratchpad);
										  }
									  }
								  }								  
								  of->write("</select></td>");
								  deleteHtmlBuffer(rtables);
							  }else
								  of->write("<td><select name=type><option>Time</select></td>");
					  }
					  snprintf(scratchpad,1024,"%d",f->dim);
					  of->write("<td><center><input type=text name=dim value=\"");
					  of->write(scratchpad);
					  of->write("\" size=4></td>");
					  of->write("<td><table><tr>");
					  of->write("<td><font color=eeee33>Mandatory</td><td><font color=eeee33>Unique</td><td><font color=eeee33>Bin</td><td><font color=eeee33>Local</td></tr>");
					  if(f->flags&HIDDEN)
						  of->write("<td><input type=hidden name=flags value=H>");
					  of->write("<td><input type=checkbox name=flags value=M");
					  if(f->flags&MANDATORY)
						  of->write(" checked=true");
					  of->write("></td><td><input type=checkbox name=flags value=U");
					  if(f->flags&UNIQUE)
						  of->write(" checked=true");
					  of->write("></td><td><input type=checkbox name=flags value=K");
					  if(f->flags&BINARY_DATA)
						  of->write(" checked=true");
					  of->write("></td><td><input type=checkbox name=flags value=L");
					  if(f->flags&LOCAL)
						  of->write(" checked=true");
					  of->write("></td></tr></table></td>");
					  of->write("<td><input type=text name=dv value=\"");
					  if(f->defaultValue){
						  if(f->type==CHAR_TYPE)
							  of->write(f->defaultValue);
						  else{
							  htmlBuffer *df=makeBuffer(f->defaultValue,f);
							  if(df){
								  of->write(*df);
								  delete df;
							  }
						  }
					  }
					  of->write("\"></tr></table></td></tr></table><input type=submit name=action value=\"Modify\"><input type=submit name=action value=\"CANCEL\"></form>");
				  }else goto info;
      }else
      if(stricmp(action,"add field")==0){
          snprintf(scratchpad,1024,"<a href=\"dbms.html?db=%s&table=%s&command=tableinfo\">Modifying <font color=eecc66>%s.%s</a><br>",dbname,tableName,dbname,tableName);
          of->write(scratchpad);
          of->write("<font color=ee3366 size=4>Add a Field</font>");
          of->write("<form method=post action=dbms.html enctype=multipart/form-data>");
          of->write("<input type=hidden name=command value=modify>\n");
          if(form->showValue("field")){
           Field *f=getField(form->showValue("field"));
           if(f!=0){
            of->write("<input type=hidden name=selected value=\"");
            of->write(f->fieldName);
            of->write("\">");
           }
          } 
          of->write("<input type=hidden name=db value=");
          of->write(dbname);
          of->write("><input type=hidden name=table value=");
          of->write(tableName);
          of->write(">");
          of->write("<table bgcolor=eecc33 cellspacing=4 cellpadding=4><tr><td><table bgcolor=cc3399 cellspacing=0><tr><td><font color=eeee33><b>Field Name</td><td><font color=eeee33><b>Type</td><td><font color=eeee33><b>Size</td><td><font color=eeee33><b>Dimension</td><td><font color=eeee33><b>Flags</td><td><font color=eeee33><b>Default Value</td><tr>");
          of->write("<td><input type=text name=fieldname value=\"\"></td>");
          of->write("<td><select name=type><option>String</option>\r\n<Option>Numeric</option>\r\n<Option>RealNumber</option>\r\n<Option>Text</option>\r\n<Option>Image</option>\r\n<Option>Time</option>\r\n");
		  htmlBuffer *rtables=getTables(dbname);
		  if(rtables){
			  of->write("<option>- - - - - - - - -</option>\r\n");
			  for(htmlBuffer* ltables=rtables;ltables!=0;ltables=ltables->next){
				  if(stricmp(*ltables,tableName)){
					  snprintf(scratchpad,128,"<OPTION>Relation->%s\r\n",(char*)*ltables);
					  of->write(scratchpad);
				  }
			  }
		  }
		  deleteHtmlBuffer(rtables);
		  of->write("</select></td>");
          of->write("<td><input type=text name=size value=1 size=4></td>");
          of->write("<td><center><input type=text name=dim value=1 size=4></td>");
          of->write("<td><table><tr>");
          of->write("<td><font color=eeee33>Mandatory</td><td><font color=eeee33>Unique</td><td><font color=eeee33>Bin</td><td><font color=eeee33>Local</td></tr>");
          of->write("<td><input type=checkbox name=flags value=M></td>");
          of->write("<td><input type=checkbox name=flags value=U></td>");
          of->write("<td><input type=checkbox name=flags value=K checked></td>");
          of->write("<td><input type=checkbox name=flags value=L></td>");
          of->write("</td></tr></table></td>");
          of->write("<td><input type=text name=dv value=\"");
          of->write("\"></tr></table></td></tr></table><input type=submit name=action value=\"ADD\"><input type=submit name=action value=\"CANCEL\"></form>");
      }else
      if(stricmp(action,"delete field")==0){
         if(form->showValue("field")){
          snprintf(scratchpad,1024,"<a href=\"dbms.html?db=%s&table=%s&command=tableinfo\">Modifying <font color=eecc66>%s.%s</a><br>",dbname,tableName,dbname,tableName);
          of->write(scratchpad);
          of->write("<font color=ee3366 size=4>Delete ");
          Field *f=getField(form->showValue("field"));
          if(f==0)
             goto info;
          of->write("Selected Field : <font color=ffffff>");
          snprintf(scratchpad,1024,"%s (Type=%s  size=%d*%d %s)",f->fieldName,translateType(f),f->size,f->dim,flagList(f->flags));
          of->write(scratchpad);
          of->write("</font>");
          of->write("<form method=post action=dbms.html enctype=multipart/form-data>");
          of->write("<input type=hidden name=command value=modify><input type=hidden name=selected value=\"");
          of->write(f->fieldName);
          of->write("\"><input type=hidden name=db value=");
          of->write(dbname);
          of->write("><input type=hidden name=table value=");
          of->write(tableName);
          of->write(">");
          of->write("<input type=submit name=action value=\"Delete\"><input type=submit name=action value=\"CANCEL\"></form>");
          }else
           goto info;
      }
   }else
   if((stricmp(command,"cancel")==0)||(stricmp(command,"tableinfo")==0)){
        info:
        snprintf(scratchpad,2048,"<table><tr><td><a href=dbms.html?command=edit&db=%s&table=%s>",dbname,tableName);
        of->write(scratchpad);
        of->write("<center><b><font size=2 color=ffffff>Click to View/Edit Contents Of <font color=ffcc66 size=4>");
        of->write(dbname);
        of->write(".");
        of->write(tableName);
        of->write("</font></a><br></td></tr></table><table border=0 bgcolor=\"ffffff\" cellpadding=2 cellspacing=1><tr bgcolor=cccccc size=2><font color=cc6699><td colspan=2>Field Name</td><td>Length</td><td>Type</td><td>Flags *</td><td>Default</td></tr>");
        int k=0;
        of->write("<form action=dbms.html method=post enctype=\"multipart/form-data\">");
        of->write("<input type=hidden name=command value=modify>");
        of->write("<input type=hidden name=db value=");
        of->write(dbname);
        of->write("><input type=hidden name=table value=");
        of->write(tableName);
        of->write(">");
        for(SField *sf=fields;sf!=0; sf = (SField *)(((Field *)*sf) ->next)){
            htmlBuffer *df=0;
            if(((Field *)*sf)->defaultValue)
             df=makeBuffer(((Field *)*sf)->defaultValue,((Field *)*sf));
			char *s=nullString;
			if(df)
				s=*df;
            if(((Field *)*sf)->flags&SYSTEM)
             snprintf(scratchpad,2048,"<tr><td bgcolor=ffcc66><br></td><font color=000000><td>%s</td><td align=right>%d*%d</td><td>%s</td><td><font color=ffffff>.<font color=000000> %s</td><td><font color=ffffff>.<font color=000000>%s</td></tr>",((Field *)*sf)->fieldName,((Field *)*sf)->size,((Field *)*sf)->dim,translateType(((Field *)*sf)),flagList(((Field *)*sf)->flags),s);
            else 
             snprintf(scratchpad,2048,"<tr><td bgcolor=ffcc66><input type=radio name=field value=\"%s\"></td><font color=000000><td>%s</td><td align=right>%d*%d</td><td>%s</td><td><font color=ffffff>.<font color=000000> %s</td><td><font color=ffffff>.<font color=000000>%s</td></tr>",((Field *)*sf)->fieldName,((Field *)*sf)->fieldName,((Field *)*sf)->size,((Field *)*sf)->dim,translateType(((Field *)*sf)),flagList(((Field *)*sf)->flags),s);
            delete df;
            of->write(scratchpad);
            k++;
            }
        of->write("<tr><td colspan=2><input type=submit name='action' value=\"Modify Field\"></td>");
        of->write("<td><input type=submit name='action' value=\"Add Field\"></td>");
        of->write("<td><input type=submit name='action' value=\"Delete Field\"></td>");
        of->write("<td><input type=submit name='action' value=\"Backup\"></td>");
        of->write("<td align=right><input type=submit name='action' value='Repair'></td></tr>");
        of->write("</table>");
        of->write("</form>");
        of->write("<font size=0 color=ffffff>* M=Mandatory,U=Unique,L=Local (Not Distributed), S=System<br>");
        snprintf(scratchpad,2048,"<font size = 3 color=cceecc>  Record Size  %d Number of Fields=%d<br>",recordSize,k);
        of->write(scratchpad);
        of->write("<br><font size = 3 color=cceecc>Number Of Records = ");
        snprintf(scratchpad,2048,"%d",dbf->getTotal());
        of->write(scratchpad);
        of->write("<br><form method=post action=dbms.html enctype=multipart/form-data>");
        of->write("<input type=hidden name=db value=");
        of->write(dbname);
        of->write("><input type=hidden name=table value=");
        of->write(tableName);
        of->write("><input type=hidden name=command value=size>");
        of->write("Maximum Records<input type=text name=maxrecords value=\"");
        if(maxRecords!=-1){
           snprintf(scratchpad,16,"%d",maxRecords);
		   of->write(scratchpad);
		}else
			of->write("No Limit");
        of->write("\"><input type=submit name=command value=SET></form></html>");
   }else{
	   int recordNo=0;
	   char *tmp=form->showValue("recordNo");
	   if(tmp && *tmp!=0)
           recordNo=atoi(tmp);
	   if(recordNo==0)
		   recordNo=(*dbf)[1];
	   char *work=form->showValue("do");
	   if(work)
		   if(stricmp(work,"next")==0){
			   recordNo=dbf->getNext(recordNo,1,1);
			   if(recordNo==0)
				   recordNo=(*dbf)[1];
		   }else
			   if(stricmp(work,"previous")==0){
				   recordNo=dbf->getNext(recordNo,-1,1);
				   if(recordNo==0)
					   recordNo=dbf->getNext(recordNo,-1,1);
			   }else
				   if(stricmp(work,"delete")==0){
					   char *v=form->showValue("action");
					   if(v){
						   if(strcmp(v,"YES")==0){
							   if(stricmp(dbname,"caravan")==0 && stricmp(tableName,"messageQueue")==0){
								   deleteQueueItem(recordNo);
							   }else
								   deleteRecord(recordNo);
						   }
					   }else{
						   of->write("<center><font size=4 color=ff000>WARNING : Record will be deleted !</font><br>");
						   of->write("Do You Want To Continue?<form action=dbms.html method=post enctype=multipart/form-data>");
						   of->write("<input type=hidden name=db value=");
						   of->write(dbname);
						   of->write("><input type=hidden name=table value=");
						   of->write(tableName);
						   of->write("><input type=hidden name=recordNo value=");
						   of->write(tmp);
						   of->write("><input type=hidden name=command value=edit><input type=hidden name=do value=delete><input type=hidden name=do value=delete><input type=submit name=action value=YES><input type=submit name=action value=NO></form>");
					   }
				   }else
					   if(stricmp(work,"modify")==0 || strcmp(work,"Add")==0){
						   int k=strcmp(work,"Add");
						   htmlObject *newValues=new htmlObject();
						   for(SField *sf=fields;sf!=0; sf = (SField *)(((Field *)*sf) ->next)){
							   if(k==0 || ( ((Field *)*sf)->type!=FILE_TYPE && ((Field *)*sf)->dim==1)){
								   htmlBuffer *v=form->getValue(((Field *)*sf)->fieldName);
								   if(v)
								   if(v!=0){
									   if(((Field *)*sf)->type==TIME_TYPE){
										   Time *tim = new Time(*v);
										   ULONG ut=*tim;
										   delete tim;
										   if(ut>0){
											   char tvs[16];
											   snprintf(tvs,16,"%ld",ut);
											   newValues->putValue(new Buffer(((Field *)*sf)->fieldName,strlen(((Field *)*sf)->fieldName)+1),new htmlBuffer(tvs));
										   }
										   delete v;
									   }else
										   newValues->putValue(new Buffer(((Field *)*sf)->fieldName,strlen(((Field *)*sf)->fieldName)+1),v);
								   }
							   }
						   }
						   if(strcmp(work,"Add")==0){
							   int n=insertRow(newValues);
							   if(n!=0)
								   recordNo=n;
						   }
						   else
							   updateRecord(newValues,recordNo);
						   delete newValues;
					   }else
						   if(stricmp(work,"GoTo")==0){
							   char *gotoRecord=form->showValue("goto");
							   if(gotoRecord)
								   recordNo=atoi(gotoRecord);
							   else
								   recordNo=(*dbf)[1];
						   }
						   char *recordExists=getRecordCached(recordNo);
						   if(stricmp(command,"size")==0){
							   char *maxrecords=form->showValue("maxrecords");
							   if(maxrecords){
								   if(stricmp(maxrecords,"no limit")==0){
									   maxRecords=-1;
									   char *b=dbf->getHeader();
									   int *nf = (int*) b;
									   nf++;
									   *nf=maxRecords;
									   dbf->putHeader();
									   goto info;
								   }else{
									   int n;
									   if(((n=atoi(maxrecords))>=dbf->getTotal()) && n != maxRecords){
										   of->write("<center><font size=4 color=ff000>WARNING<BR>Setting the maximum record size may cause some records to be deleted !!!</font><br>");
										   of->write("Do You Want To Continue?<form action=dbms.html method=post enctype=multipart/form-data>");
										   of->write("<input type=hidden name=db value=");
										   of->write(dbname);
										   of->write("><input type=hidden name=table value=");
										   of->write(tableName);
										   of->write("><input type=hidden name=maxrecords value=");
										   of->write(maxrecords);
										   of->write("><Input type=submit name=command value=YES><input type=submit name=command value=CANCEL></form>");
									   }else
										   goto info;
								   }
							   }else
								   goto info;
						   }else
							   if(stricmp(command,"YES")==0){
								   char *mx=form->showValue("maxrecords");
								   int n;
								   if(mx && (n=atoi(mx))>dbf->getTotal() && (n!=maxRecords)){
									   maxRecords=atoi(mx);
									   char *b=dbf->getHeader();
									   int *nf = (int*) b;
									   nf++;
									   *nf=maxRecords;
									   dbf->putHeader();
								   }
								   goto info;
							   }else
								   if(stricmp(command,"edit")==0){
									   int blank=0;
									   snprintf(scratchpad,1024,"<center><font size=4 color=ffffff>Table <a href=\"dbms.html?command=tableinfo&db=%s&table=%s\"><font color=ffcc66>%s.%s</a></font> Record <font color=ffee66>%d<br></font>",form->showValue("db"),form->showValue("table"),dbname,tableName,recordNo);
									   of->write(scratchpad);
									   of->write("<table bgcolor=339966><tr><td>\r\n<form METHOD=POST action=dbms.html ENCTYPE=\"multipart/form-data\">");
									   of->write("<input type=hidden name=command value=edit>");
									   of->write("<input type=hidden name=db value=");
									   of->write(form->showValue("db"));
									   of->write("><input type=hidden name=table value=");
									   of->write(form->showValue("table"));
									   of->write("><font size=-1 color=ff0000><center>");
									   of->write("<input type=\"submit\"  name=\"do\" value=\"Next\">");
									   of->write("<input type=\"submit\"  name=\"do\" value=\"Previous\">");
									   if(work && stricmp(work,"new")==0){
										   of->write("<input type=\"submit\"  name=\"do\" value=Add>");
										   blank=1;
									   }else{
										   if(recordExists){
											   of->write("<input type=\"submit\"  name=\"do\" value=Modify>");
										   }
										   of->write("<input type=\"submit\"  name=\"do\" value=New>");
									   }
									   of->write("<input type=\"submit\"  name=\"do\" value=GoTo>");
									   of->write("<input type=\"hidden\" name=\"recordno\" value=");
									   snprintf(scratchpad,16,"%d>",recordNo);
									   of->write(scratchpad);
									   of->write("<input type=\"text\" name=\"GOTO\" value=");
									   snprintf(scratchpad,16,"%d",recordNo);
									   of->write(scratchpad);
									   of->write(" size=10 maxlength=10>");
									   if(recordExists && ((work==0) || stricmp(work,"delete"))){
										   of->write("<input type=\"submit\"  name=\"do\" value=Delete>");
									   }
									   of->write("</center></td></tr>\n<tr><td>");
									   if(recordExists || blank){
										   of->write("<center><table border=0 cellpadding=2 cellspacing=0 bgcolor=66cc99 width=100%>");
										   of->write("<tr bgcolor=eeee33><td><b><font size=4>Field Name</td><td align=right><font size=4><b>Contents</td></tr>\n");
										   char *fdata=scratchpad+1024;
										   *fdata=0;
										   for(SField *sf=fields;sf!=0; sf = (SField *)(((Field *)*sf) ->next)){
											   htmlBuffer *v=0;
											   if(blank==0){
												   v=getFieldValue(recordNo,0,((Field *)*sf));
											   }else{
												   if(((Field *)*sf)->flags&SYSTEM)
													   continue;
												   if(((Field *)*sf)->defaultValue){
													   v=makeBuffer(((Field *)*sf)->defaultValue,((Field *)*sf));
												   }
											   }
											   htmlBuffer *t=0;
											   if(!blank && ((((Field *)*sf)->dim>1) || ((Field *)*sf)->type==FILE_TYPE)){
												   snprintf(scratchpad,1024,"<tr><td><b><font color=ffffff size=4><i>%s</i></td><td align=right><select name=\"%s\">",((Field *)*sf)->fieldName,((Field *)*sf)->fieldName);
												   of->write(scratchpad);
												   while(v){
													   t=v;
													   v=v->next;
													   strcpy(fdata,"\n<option>");
													   int l=9;
													   if(((Field *)*sf)->type==FILE_TYPE){
														   File *fd;
														   if((fd=t->getFile())!=0){
															   strcpy(fdata+l,fd->getRealName());
															   l+=strlen(fdata+l);
														   }
													   }else{
														   if(((Field *)*sf)->flags&HIDDEN){
															   strcpy(fdata+l,"******");
															   l+=6;
														   }
														   else{
															   if(((Field *)*sf)->type==TIME_TYPE){
																   Time *tim=new Time((ULONG) atoi(*t));
																   strncpy(fdata+l,tim->local(),48);
																   l+=strlen(fdata+l);
																   delete tim;
															   }else{
																   int lim=strlen(*t);
																   if(lim>48)
																	   lim=48;
																   memcpy(fdata+l,(char*)*t,lim);
																   l+=lim;
																   fdata[l]=0;
															   }
														   }
													   }
													   strcpy(fdata+l,"\n");
													   delete t;
													   of->write(fdata);
												   }
												   if(t)
													   of->write("</select></td></tr>\n");
												   else
													   of->write("<br></td></tr>\n");
											   }else{
												   int hide=((Field *)*sf)->flags&HIDDEN;
												   int l;
												   if(((Field *)*sf)->type==FILE_TYPE)
													   l=snprintf(fdata,3024,"<input type=file name = %s value=\"",((Field *)*sf)->fieldName);
												   else
													   l=snprintf(fdata,3024,"<input type=\"%s\" name = \"%s\" size=\"32\" maxlength=\"%d\" value=\"",(hide?sPSWD:"text"),((Field *)*sf)->fieldName,charWidth(((Field *)*sf)));
												   char *dataval=fdata+l;
												   if(v){
													   if(hide)
														   strcpy(dataval,"******");
													   else
														   if(((Field *)*sf)->type==TIME_TYPE){
															   Time *tim=new Time((ULONG) atoi(*v));
															   strncpy(dataval,tim->local(),48);
															   delete tim;
														   }else
															   strcpy(dataval,*v);
														   dataval+=strlen(dataval);
														   delete v;
												   }
												   strcpy(dataval,"\">");
												   snprintf(scratchpad,1024,"<tr><td><b><font color=ffffff size=4><i>%s</i></td><td align=right>%s</td></tr>\n",((Field *)*sf)->fieldName,fdata);
												   of->write(scratchpad);
											   }
										   }
										   of->write("<tr><td colspan=2 bgcolor=ffffff><font size=1><b><i>Copyright (c) Caravan Software</td></tr>\n</table></form>");
									   }else{
										   of->write("<center><font size=5 color=ff0000> Record Does Not Exist</center>");
									   }
									   of->write("</td></tr>\n</table></html>");
          }
         }
  }
}
delete tmpbuff;
}





void Table::getTableDef()
{
	int calc=0;
reCalc:
	calc++;
	if(calc==3){
		char wsc[256];
		snprintf(wsc,256,"%s%c%s.db%c%s.xml",dbHome,FSLASH,dbname,FSLASH,tableName);
		File *f=new File(wsc);
		if(f->size()>0){
			htmlBuffer *z=new htmlBuffer(f);
			xmlObject *xml=new xmlObject(0,z);
			f->close();
			f->deleteFile();
			delete z;
			makeTable(xml);
			delete xml;
		}else
			delete f;
		RepairTable();
		return;
	}
	SField *sf;
	int totalr=dbf->getTotal();
	char *b=dbf->getHeader();
	if(b==0)
		return;
	char *hb=b;
	int *nf = (int*) b;
	Field *f;
	int offset = 0;
	fields = 0;
	if((*nf>0) && (*nf < MAXFIELDS)){
		b+=sizeof(int);
		maxRecords=*((int*)b);
		b+=sizeof(int);
		for(int i=0;i<*nf;++i){   
			sf = new SField();
			f=*sf;
			memcpy((char*) f,b,FIELDSIZE);
			f->hdOffset=b-hb;
			b+=FIELDSIZE;
			if(totalr <= 1){
				if(f->root!=0){
					f->root=0;
					f->unodes=0;
					memcpy(hb+f->hdOffset,f,FIELDSIZE);
					totalr=0;
				}
			}
			f->next = fields;
			f->offset = offset+sizeof(char);
			offset += getFieldSize(f);
			fields = sf;
		}
	}
	getRecordSize();
	if(recordSize!=dbf->getRecordSize()){
		fileInfoSize-=64;
		recordSize=0;
		goto reCalc;
	}
	if(totalr==0){
		dbf->putHeader();
		dbf->flush();
	}
	defaultCache = new Buffer(recordSize);
	if(dbf->get(defaultCache,0)){
		for(sf=fields;sf!=0;sf = (SField *)(((Field *)*sf) ->next)){
			f = *sf;
			f->defaultValue = (char*)*defaultCache;
			f->defaultValue+=getFieldOffset(f);
			if(f->type==INDEX_TYPE)
				f->defaultValue=nullString;
			
		}
	}else{
		for(sf=fields;sf!=0;sf = (SField *)(((Field *)*sf) ->next)){
			f = *sf;
			f->defaultValue = nullString;
		}
		delete defaultCache;
		defaultCache = 0;
	}
}


int Table::getKeyRecord(char* fieldName,char* val)
{
   Field *f=getField(fieldName);
   if((f!=0) && (f->flags&UNIQUE)){
	Buffer *tmpBuf=new Buffer(f->size*elementSize(f->type));
    char *tmp=*tmpBuf;
    evaluate(tmp,val,f);
    int recId=searchTree(tmp,f);
	delete tmpBuf;
    return(recId);
   }
   return 0;
}

void deleteRelated(char*dbname,char*tablename,char*fieldname,int rel);
int delet=0;
void Table::deleteRecord(int recordNo,htmlBuffer *from,int mdel)
{
	if(dbf==0 || recordNo==0)
		return;
	lock();
	if(recordNo==-1)
		recordNo=(*dbf)[1];
	char *tmpbuff=getRecordCached(recordNo);
	if (tmpbuff==0){
		release();
		return;
	}
	Buffer *wbBuff=new Buffer(sizeof(void*)*MAXFIELDS);
	char *wb=*wbBuff;
	memset(wb,0,(sizeof(void*)*MAXFIELDS));
	WordBasket **wbs=(WordBasket**)wb;
	if(removeFiles(tmpbuff,recordNo,(void **)wb)){
		int updateHeader=0;
		char *tmpHeader=dbf->getHeader();
		Field *f;
		htmlBuffer *arg=new htmlBuffer(dbname);
		arg->next=new htmlBuffer(tableName);
		char tmp[16];
		snprintf(tmp,16,"%d",recordNo);
        arg->next->next=new htmlBuffer(tmp);
		arg->next->next->next=new htmlBuffer(tmp);
		if(mdel==0)
			syslog("delete",from,arg);
		dbf->bufferedPut(tmpbuff,recordNo);
		for(SField* sf=fields;sf!=0;sf=(SField*)f->next){
			f=*sf;
			if(getFieldDim(tmpbuff,f)>0){
				int r=deleteNode(recordNo,f);
				if(r<0){
					char tmp[256];
					snprintf(tmp,256,"Unrecoverable Error : (EDD) deleting field %s from r%d %d\n",f->fieldName,recordNo,r);
					exitTableError(-2,tmp);
				}else
					if(r>0){
						updateHeader++;
						memcpy(tmpHeader+f->hdOffset,f,FIELDSIZE);
					}
			}
		}
		if(updateHeader)
			dbf->bufferedPutHeader();
		removeFromSelections(recordNo);
		dbf->bufferedDeleteRecord(recordNo);
		dbf->flushDat();
		DeleteCachedRecord(recordNo);
		//		delRecordFromCache(recordNo);
		release();
		for(int i=0;wbs[i]!=0;++i)
			delete wbs[i];
		for(htmlBuffer* cT=childs;cT!=0;cT=cT->next)
			deleteRelated(dbname,*cT,tableName,recordNo);
	}else{
		release();
		for(int i=0;wbs[i]!=0;++i)
			delete wbs[i];
	}
	if(needsRepair){
		RepairTableOnline();
	}
	delete wbBuff;
}


void shutDown();

void Table::exitTableError(int n,char* s)
{
	dbf->forceRepair();
	char tmp[512];
	snprintf(tmp,512,"[%s.%s] :  %s\n",dbname,tableName,s);
	caravanlog(tmp);
	printf("%s\n",tmp);
	needsRepair=1;
	/*
	shutDown();
	SleepMilSec(2000);
	exit(n);
	*/
}

void Table::RepairTableOnline()
{
	lock();
	dbf->forceRepair();
	if(dbf->reopen()){
		release();
		if (cleanSearch()){
			lock();
			RepairTable();
			release();
		}
	}else
		release();
	if(needsRepair){
		shutDown();
		SleepMilSec(1000);
		exit(-32);
	}
}


int Table::checkTree(Field *f,int recId)
{
	if(f->type==FILE_TYPE)
		return 0;
	char tmp[256];
	tmp[0]=0;
	char* tmpbuff=getRecordCached(recId);
	int erec=recId;
	if(tmpbuff){
		recordInfo* newnode=(recordInfo*)(tmpbuff+f->offset);
		if(newnode->balance>1 || newnode->balance<-1){
			snprintf(tmp,256,"[%s(%d)@%s.%s] : invalid balance",f->fieldName,recId,dbname,tableName);
			caravanlog(tmp);						
		}
		if(newnode->parent){
			char *recbuff=getRecordCached(newnode->parent);
			if(recbuff){
				int d=compare(recbuff+getFieldOffset(f),tmpbuff+getFieldOffset(f),f->type);
				recordInfo* node=(recordInfo*)(recbuff+f->offset);
				if(node->center==recId){
					if(newnode->centerWeight!=-1 || d!=0){
						snprintf(tmp,256,"EQU1[%s(%d)@%s.%s] : invalid center node %d",f->fieldName,recId,dbname,tableName,d);
						caravanlog(tmp);						
					}
				}else{
					if(node->left==recId ){
						if(d<=0){
							snprintf(tmp,256,"C1[%s(%d)@%s.%s] : parent!>child",f->fieldName,recId,dbname,tableName);
							caravanlog(tmp);						
						}
						if(node->leftWeight!=(newnode->leftWeight+newnode->rightWeight+newnode->centerWeight+1)){
							snprintf(tmp,256,"L[%s(%d)@%s.%s] : parent/child weight mismatch",f->fieldName,recId,dbname,tableName);
							caravanlog(tmp);						
						}
					}else
						if(node->right==recId){
							if(d>=0){
								snprintf(tmp,256,"C1[%s(%d)@%s.%s] : parent!<child",f->fieldName,recId,dbname,tableName);
								caravanlog(tmp);						
							}
							if(node->rightWeight!=(newnode->leftWeight+newnode->rightWeight+newnode->centerWeight+1)){
								snprintf(tmp,256,"R[%s(%d)@%s.%s] : parent/child weight mismatch",f->fieldName,recId,dbname,tableName);
								caravanlog(tmp);						
							}
						}
				}
			}else{
				erec=recId;
				goto errAccess;
			}
		}else{
			if(f->root!=recId){
				if(getFieldDim(tmpbuff,f)==0){
					int i=0;
					for(char *b=(char*)newnode;i<sizeof(recordInfo);++i){
						if(b[i]!=0){
							snprintf(tmp,256,"MT[%s(%d)@%s.%s] : contains invalid links",f->fieldName,recId,dbname,tableName);
							caravanlog(tmp);
							break;
						}
					}
				}else{
					snprintf(tmp,256,"UL[%s(%d)@%s.%s] : orphan, invalid root %d %d %d",f->fieldName,recId,dbname,tableName,f->root,newnode->left,newnode->right);
					caravanlog(tmp);	
				}
			}
		}
		if(newnode->center){
			char *recbuff=getRecordCached(newnode->center);
			int d=compare(recbuff+getFieldOffset(f),tmpbuff+getFieldOffset(f),f->type);
			if(d!=0){
				snprintf(tmp,256,"C2[%s(%d)@%s.%s] : parent!=child",f->fieldName,recId,dbname,tableName);
				caravanlog(tmp);						
			}
			if(recbuff){
				recordInfo* node=(recordInfo*)(recbuff+f->offset);
				if(node->parent==recId){
					if(node->centerWeight!=-1){
						snprintf(tmp,256,"EQU2[%s(%d)@%s.%s] : contains centrenode",f->fieldName,newnode->center,dbname,tableName);
						caravanlog(tmp);						
					}	
				}else{
					snprintf(tmp,256,"EQU2[%s(%d)@%s.%s] : parent mismatch",f->fieldName,newnode->center,dbname,tableName);
					caravanlog(tmp);						
				}
			}else{
				erec=newnode->left;
				goto errAccess;
			}
		}
		if(newnode->left){
			char *recbuff=getRecordCached(newnode->left);
			int d=compare(recbuff+getFieldOffset(f),tmpbuff+getFieldOffset(f),f->type);
			if(d>=0){
				snprintf(tmp,256,"C2[%s(%d)@%s.%s] : parent!<child",f->fieldName,recId,dbname,tableName);
				caravanlog(tmp);						
			}
			if(recbuff){
				recordInfo* node=(recordInfo*)(recbuff+f->offset);
				if(node->parent==recId){
					if(newnode->leftWeight!=(node->leftWeight+node->rightWeight+node->centerWeight+1)){
						snprintf(tmp,256,"L[%s(%d)@%s.%s] : parent/child weight mismatch",f->fieldName,newnode->left,dbname,tableName);
						caravanlog(tmp);						
					}
				}else{
					snprintf(tmp,256,"L[%s(%d)@%s.%s] : parent mismatch",f->fieldName,newnode->left,dbname,tableName);
					caravanlog(tmp);						
				}
			}else{
				erec=recId;
				goto errAccess;
			}
		}
		if(newnode->right){
			char *recbuff=getRecordCached(newnode->right);
			int d=compare(recbuff+getFieldOffset(f),tmpbuff+getFieldOffset(f),f->type);
			if(d<=0){
				snprintf(tmp,256,"C2[%s(%d)@%s.%s] : parent!>child",f->fieldName,recId,dbname,tableName);
				caravanlog(tmp);						
			}
			if(recbuff){
				recordInfo* node=(recordInfo*)(recbuff+f->offset);
				if(node->parent==recId){
					if(newnode->rightWeight!=(node->leftWeight+node->rightWeight+node->centerWeight+1)){
						snprintf(tmp,256,"R[%s(%d)@%s.%s] : parent/child weight mismatch",f->fieldName,newnode->right,dbname,tableName);
						caravanlog(tmp);						
					}					
				}else{
					snprintf(tmp,256,"R[%s(%d)@%s.%s] : parent mismatch",f->fieldName,newnode->right,dbname,tableName);
					caravanlog(tmp);										
				}
			}else{
				erec=newnode->right;
				goto errAccess;
			}
		}
	}else{
errAccess:
	snprintf(tmp,256,"[%s(%d)@%s.%s] : cannot get record",f->fieldName,erec,dbname,tableName);
	caravanlog(tmp);		
	}
	return tmp[0];
}



int Table::insertRow(genericObject *data,int system)
{
	char fieldId[64];
	char* origin=0;
	char *c;
	SField *sf;
	htmlBuffer *v;
	Field *f;
	Buffer *tmpbuff = new Buffer(getRecordSize());
	c = *tmpbuff;
	Buffer *wbBuff=0;
	WordBasket** wbs;
	int wbt=0;
	int recId=0;
	int fileId=0;
	FILEINFO* urecIdHere=0;
	int i=0;
	for(sf=fields;sf!=0;sf=(SField*)f->next){		// get fileId while copying records from backup table.
		f=*sf;										// File types are desguised as BIN_TYPE
		if(f->type==BIN_TYPE){
			char *s=data->showValue(f->fieldName);
			if(s!=0){
				v=data->getValue(f->fieldName,i);
				if(v->getSize()==fileInfoSize){
					FILEINFO* finfo=(FILEINFO*)s;
					if(v->isValid()){
						if(finfo->recId!=0){
							fileId=finfo->recId;
						}
					}else{
						if((finfo->fieldId==MAXINT) && (finfo->size==MAXINT) && (finfo->recId!=0)){
							fileId=finfo->recId;
						}
					}
				}
				delete v;
				if(fileId!=0)
					break;
			}
		}
	}
	for(sf=fields;sf!=0;sf=(SField*)f->next){
		WordBasket *wb=0;
		i=0;
		f=*sf;
		memset(c+f->offset-sizeof(char),0,sizeof(recordInfo)+sizeof(char));
		if((urecIdHere==0) && ((f->type==FILE_TYPE) || (f->type==BIN_TYPE))){
			urecIdHere=(FILEINFO*)(c+getFieldOffset(f));
			urecIdHere->recId=0;
		}
		if(((f->flags&(SYSTEM|HIDDEN))==0) || system) {
			if(((f->flags&BINARY_DATA)==0) &&
				((f->type==CHAR_TYPE) || (f->type==FILE_TYPE))){
				snprintf(fieldId,64,"%s.%s.%s",dbname,tableName,f->fieldName);
				if(wbBuff==0){
					wbBuff=new Buffer(sizeof(void*)*MAXFIELDS);
					wbs=(WordBasket**)((char*)*wbBuff);
				}
				wb=wbs[wbt++]=new WordBasket(fieldId);
			}
			int j=0;
			do{
				if((v=data->getValue(f->fieldName,j++))!=0){
					if(v->getFile() || *((char*)*v) || (f->type==BIN_TYPE)){
						char* destp=c+getFieldOffset(f)+i*f->size*elementSize(f->type);
						fileId=evaluate(destp,v,f,fileId,i);
						if(wb)
							wb->putWords(v,NEWWORD);
						if(f->type==INDEX_TYPE){
							if(checkValidRelation(dbname,f->tableName,*(int*)destp))
								i++;
						}else{
							if(v->isValid()){
								i++;
							}
						}
					}
					delete v;
				}
			}while(v && i<f->dim);
		}
		if(i>0){
			putFieldDim(c,f,i);
		}else{
			if(f->flags&MANDATORY){
				goto abortInsert;
			}else{
				if(strcmp(sORIGIN,f->fieldName)==0)
					origin=location;
				else{
					char *dv=f->defaultValue;
					int i=0;
					if(dv && (*dv || f->type==INDEX_TYPE)){
						for(;i<f->dim;i++)
							memcpy(c+getFieldOffset(f)+i*f->size*elementSize(f->type),dv,f->size*elementSize(f->type));
					}
					putFieldDim(c,f,i);
				}
			}
		}
		if(f->flags&UNIQUE){
			if(searchTree(c+getFieldOffset(f),f)!=0){
				goto abortInsert;
			}
		}
	}
	if((maxRecords!=-1) && dbf->getTotal()>maxRecords)
		deleteRecord(-1);
	lock();
	if((urecIdHere!=0) && (urecIdHere->recId==0)){
		if(fileId==0)
			urecIdHere->recId=dbf->incUrecId();
		else
			urecIdHere->recId=fileId;
		urecIdHere->fieldId=MAXINT;
		urecIdHere->size=MAXINT;
	}
	recId=dbf->getNewRecordNo();
	cacheRecord(tmpbuff,recId);
	dbf->bufferedAdd(*tmpbuff,recId);
	tmpbuff=0;
	if((c = getRecordCached(recId))!=0){
		if(origin==location){
			if((f=getField(sORIGIN))!=0){
				putFieldDim(c,f,1);
				snprintf(c+getFieldOffset(f),f->size-1,"%s%u",location,recId);
			}
		}
		int updateHeader=0;
		char *tmpHeader=dbf->getHeader();
		for(sf=fields;sf!=0;sf=(SField*)f->next){
			f=*sf;
			if(getFieldDim(c,f)>0){
				int r=insertNode(recId,f);
				if(r<0){
					char tmp[256];
					snprintf(tmp,256,"Unrecoverable Error : (EII) inserting field %s in r%d %d\n",f->fieldName,recId,r);
					exitTableError(-1,tmp);
				}
				updateHeader++;
				memcpy(tmpHeader+f->hdOffset,f,FIELDSIZE);
			}
		}
		if(updateHeader)
			dbf->bufferedPutHeader();
		dbf->flushDat();
		updateSelections(c,recId);
	}
	release();
abortInsert:
	delete tmpbuff;
	for(i=0;i<wbt;++i){
		if(wbs[i]){
			wbs[i]->setRecId(recId);
			delete wbs[i];
		}
	}
	delete wbBuff;
	if(system!=2 && recId!=0){
		htmlBuffer *arg=new htmlBuffer(dbname);
		arg->next=new htmlBuffer(tableName);
		snprintf(fieldId,16,"%d",recId);
        arg->next->next=new htmlBuffer(fieldId);
		syslog("insert",data->getValue(sFROM),arg);
	}
	if(needsRepair){
		RepairTableOnline();
	}
	return recId;
}



int Table::updateRecord(genericObject *data,int recordNo,int system)
{
	char fieldId[64];
	htmlBuffer *v;
	int recId=-1;
	SField *sf;
	Field *f;
	htmlBuffer *fieldList=0,*lfield=0;
	if(dbf->isValidRecord(recordNo)==0)
		return 0;
	if((system==0) && dbf->nomodify())
		return 0;
	Buffer *wbBuff=0;
	WordBasket** wbs;
	int wbt=0;
	lock();
	char* oldData = getRecordCached(recordNo);
	if(oldData==0){
		release();
		return 0;
	}
	int locked=1;
	Buffer *tmpbuff = new Buffer(oldData,getRecordSize());
	char *c=*tmpbuff;
	int fileId=0;
	int updated=0;
	int i,j;
	for(sf=fields,i=0;sf!=0;sf=(SField*)f->next){
		f=*sf;
		if(f->type==FILE_TYPE){
			if(getFieldDim(c,f)>0){
				if((fileId=((FILEINFO*)(c+getFieldOffset(f)))->recId)!=0)
					break;
			}else{
				FILEINFO* urecIdHere=((FILEINFO*)(c+getFieldOffset(f)));
				if(urecIdHere->size==MAXINT && urecIdHere->fieldId==MAXINT && (urecIdHere->recId!=0)){
				 fileId=urecIdHere->recId;
				 break;
				}
			}
			i+=data->hasProperty(f->fieldName);
		}
	}
	if((i==0) || (fileId!=0)){
		locked=0;
		release();
	}
	for(sf=fields;sf!=0;sf=(SField*)f->next){
		f=*sf;
		if(data->hasProperty(f->fieldName)){
			if(((f->flags&(SYSTEM|HIDDEN))==0) || system) {
				htmlBuffer *cold=getFieldValue(recordNo,0,f);
				i=0;
				j=0;
				WordBasket *wb=0;
				if(((f->flags&BINARY_DATA)==0) &&
					((f->type==CHAR_TYPE) || (f->type==FILE_TYPE))){
					snprintf(fieldId,64,"%s.%s.%s",dbname,tableName,f->fieldName);
					if(wbBuff==0){
						wbBuff=new Buffer(sizeof(void*)*MAXFIELDS);
						wbs=(WordBasket**)((char*)*wbBuff);
					}
					wb=wbs[wbt++]=new WordBasket(fieldId);
					for(v=cold;v!=0;v=v->next)
						wb->putWords(v,OLDWORD);
				}
				do{
					htmlBuffer* cdel=0;
					if((v=data->getValue(f->fieldName,i))!=0){
						if(wb)
							wb->putWords(v,NEWWORD);
						if(v->equals(cold,1)==0){
							char* destp=c+getFieldOffset(f)+i*f->size*elementSize(f->type);
							if(v->getFile() || strlen(*v)) {
								if(f->type==FILE_TYPE && getFieldDim(c,f)>(ULONG)i){
									if(((FILEINFO*)destp)->recId!=0){
										fileId=((FILEINFO*)destp)->recId;
									}
								}
								int prevVal=*((int*)destp);
								if(cold){
									cdel=cold;
									cold=cold->next;
									delete cdel;
								}
								fileId=evaluate(destp,v,f,fileId,i);
								if(locked && fileId){
									release();
									locked=0;
								}
								if(f->type==INDEX_TYPE){
									if(locked) release();
									if(checkValidRelation(dbname,f->tableName,*(int*)destp)==0)
										*((int*)destp)=prevVal;
									if(locked) lock();
								}
								j++;
							}else{
								if((f->type==INDEX_TYPE) && ((f->flags&MANDATORY)==0)){
									*((int*)destp)=0;
									j++;
								}
							}
						}else
							j++;
						i++;
						delete v;
						if(cdel==0){
							if(cold){
								cdel=cold;
								cold=cold->next;
								delete cdel;
							}
						}
					}
				}while(v && i<f->dim);
				deleteHtmlBuffer(cold);
				if(j || getFieldDim(c,f)){
					putFieldDim(c,f,j);
					htmlBuffer *fb=new htmlBuffer(f->fieldName);
					if(fieldList==0)
						fieldList=fb;
					else
						lfield->next=fb;
					lfield=fb;
					if((j==0) && f->flags&MANDATORY)
						updated|=MANDATORY;
					if(f->flags&UNIQUE)
						updated|=UNIQUE;
				}
			}
		}
	}
	if(locked==0)
		lock();
	if(fieldList && ((oldData=getRecordCached(recordNo))!=0)){
		htmlBuffer *fl=fieldList;
		if(updated&MANDATORY){
			for(;fl!=0;fl=fl->next){
				f=getField(*fl);
				if((f->flags&MANDATORY) && (getFieldDim(c,f)==0)){
					deleteRecord(recordNo);
					goto done;
				}
			}
		}
		if(updated&UNIQUE){
			for(fl=fieldList;fl!=0;fl=fl->next){
				f=getField(*fl);
				if(f->flags&UNIQUE){
					if((recId=searchTree(c+getFieldOffset(f),f))!=0){
						if(recId!=recordNo){
done:
						release();
						delete tmpbuff;
						deleteHtmlBuffer(fieldList);
						for(i=0;i<wbt;++i)
							delete wbs[i];
						delete wbBuff;
						return 0;
						}
					}
				}
			}
		}
		dbf->bufferedPut(oldData,recordNo);
		updated=0;
		int updateHeader=0;
		char *tmpHeader=dbf->getHeader();
		Buffer* tmp=new Buffer(oldData,getRecordSize());
		char *cdata=*tmp;
		htmlBuffer *prev=0;
		for(fl=fieldList;fl!=0;){
            int ups=updated;
			f=getField(*fl);
			i=getFieldDim(c,f);
			if(f->type==FILE_TYPE){
				removeFiles(c,f,i);
				renameFiles(c,f,i);
			}
			int l=getFieldOffset(f);
			j=getFieldDim(oldData,f);
			putFieldDim(oldData,f,i);
			if(i>0){
				if(j>0){
					if(f->type==FILE_TYPE){
						fileId=0;
						updated++;
					}else{
						if((fileId=compare(cdata+l,c+l,f->type))==0){
							if(i==j){
								for(j=0;j<i;++j){
									if(CompareCase(cdata+l+j*f->size*elementSize(f->type),
										c+l+j*f->size*elementSize(f->type),f->type)){
										updated++;
										break;
									}
								}
							}else
								updated++;
						}
					}
					memcpy(oldData+l,c+l,i*f->size*elementSize(f->type));
					if(fileId){
						updated++;
						int r=modifyNode(recordNo,f);
						if(r<0){
							char tmp[256];
							snprintf(tmp,256,"Unrecoverable Error : (EUD) modifying field %s from r%d %d\n",f->fieldName,recordNo,r);
							exitTableError(-2,tmp);
						}else{
							if(r>0){
								updateHeader++;
								memcpy(tmpHeader+f->hdOffset,f,FIELDSIZE);
							}
						}
					}
				}else{
					memcpy(oldData+l,c+l,i*f->size*elementSize(f->type));
					updated++;
					int r=insertNode(recordNo,f);
					if(r<0){
						char tmp[256];
						snprintf(tmp,256,"Unrecoverable Error : (EUI) inserting field %s in r%d %d\n",f->fieldName,recordNo,r);
						exitTableError(-1,tmp);
					}else{
						if(r>0){
							updateHeader++;
							memcpy(tmpHeader+f->hdOffset,f,FIELDSIZE);
						}
					}
				}
			}else{
				if(j>0){
					updated++;
					if(f->type==FILE_TYPE){
						((FILEINFO*)(oldData+l))->size=((FILEINFO*)(oldData+l))->fieldId=MAXINT;
					}else{
						int r=deleteNode(recordNo,f);
						if(r<0){
							char tmp[256];
							snprintf(tmp,256,"Unrecoverable Error : (EUD) deleting field %s from r%d %d\n",f->fieldName,recordNo,r);
							exitTableError(-2,tmp);
						}
						else{
							if(r>0){
								updateHeader++;
								memcpy(tmpHeader+f->hdOffset,f,FIELDSIZE);
							}
						}
					}
					memset(oldData+f->offset,0,sizeof(recordInfo));
				}
			}
			if(updated==ups){
				if(prev==0){
					fieldList=fl->next;
					delete fl;
					fl=fieldList;
				}else{
					prev->next=fl->next;
					delete fl;
					fl=prev->next;
				}
			}else{
				prev=fl;
				fl=fl->next;
			}
		}
		if(updated){
			setChanged(recordNo);
			dbf->bufferedPut(oldData,recordNo);   
			if(updateHeader)
				dbf->bufferedPutHeader();
		}
		dbf->flushDat();
		if(updated && fieldList){
			updateSelections(oldData,recordNo,fieldList,cdata);
		}
		delete tmp;
	}else
	   recordNo=0;
	release();
    delete tmpbuff;
	for(i=0;i<wbt;++i){
		if(wbs[i]){
			wbs[i]->setRecId(recordNo);
			delete wbs[i];
		}
	}
	delete wbBuff;
	if(system!=2 && recordNo && fieldList){
		htmlBuffer *arg=new htmlBuffer(dbname);
		arg->next=new htmlBuffer(tableName);
		snprintf(fieldId,16,"%d",recordNo);
        arg->next->next=new htmlBuffer(fieldId);
		arg->next->next->next=fieldList;
		syslog("modify",data->getValue(sFROM),arg);
	}
	if(needsRepair){
		RepairTableOnline();
	}
	return recordNo;
}




int Table::removeFiles(char *c,int recordNo,void** wbs)
{
	int wbt=0;
	SField *sf;
	Field *f;
	char fieldId[64];
	for(sf=fields;sf!=0;sf=(SField*)f->next){
		f=*sf;
		if(((f->flags&BINARY_DATA)==0) &&
			((f->type==CHAR_TYPE) || (f->type==FILE_TYPE))){
			snprintf(fieldId,64,"%s.%s.%s",dbname,tableName,f->fieldName);
			WordBasket *wb=new WordBasket(fieldId,recordNo);
			wbs[wbt++]=wb;
			htmlBuffer* v=getFieldValue(recordNo,0,f);
			while(v){
				wb->putWords(v,OLDWORD);
				htmlBuffer *t=v;
				v=v->next;
				delete t;  
			}
		}
		if(f->type==FILE_TYPE)
			if(removeFiles(c,f)==0)
				return 0;
	}
	return 1;     
}

int Table::removeFiles(char *recbuff,Field* f,int fr)
{
	int success=1;
	if(f->type==FILE_TYPE){
        int i;
        int fsize=f->size*elementSize(f->type);
        int fdim=getFieldDim(recbuff,f);
		if(fdim==0 && fr==0){
			fdim=1;
		}
		if(fdim>0){
			FILEINFO *finfo;
			Buffer *pb=new Buffer((i=strlen(*name))+strlen(f->fieldName)+20);
			char *p=*pb;
			strcpy(p,*name);
			for(;i>0 && p[i]!=FSLASH;--i){
				if(p[i]=='.')
					break;
			}
			if(p[i]=='.'){
				i++;
				strcpy(p+i,f->fieldName);
				i=strlen(p);
				p[i++]=FSLASH;
				for(int fn=fr;fn<fdim;++fn){
					finfo=(FILEINFO*) (recbuff+getFieldOffset(f) + fsize*fn);
					printFilename(p+i,finfo->recId,finfo->fieldId);
					File *fp=new File(p);
					if(fp->deleteFile()==0)
						success=0;
					delete fp;
				}
			}
			delete pb;
		}
	}
	return success;
}

int Table::renameFiles(char *recbuff,Field* f,int fr)
{
	int success=1;
	if((f->type==FILE_TYPE) && (fr > 0)){
        int i;
        int fsize=f->size*elementSize(f->type);
        FILEINFO *finfo;
		Buffer *pb=new Buffer((i=strlen(*name))+strlen(f->fieldName)+32);
		char *p=*pb;
        strcpy(p,*name);
        for(;i>0 && p[i]!=FSLASH;--i){
			if(p[i]=='.')
				break;
		}
		if(p[i]=='.'){
			i++;
			strcpy(p+i,f->fieldName);
			i=strlen(p);
			p[i++]=FSLASH;
			for(int fn=0;fn<fr;++fn){
				finfo=(FILEINFO*) (recbuff+getFieldOffset(f) + fsize*fn);
				if (finfo->fieldId>=1000){
					printFilename(p+i,finfo->recId,finfo->fieldId);
					File *fp=new File(p);
					if(fp->open()){
						printFilename(p+i,finfo->recId,fn);
						int e=-1;
						fp->close();
						for(int k=0;k<30;++k){
							if(e==-1)
								e=unlink(p);
							if(fp->rename(p)){
								finfo->fieldId=fn;
								break;
							}
							SleepMilSec(100);
						}
					}
					delete fp;
				}
			}
		}
		delete pb;
	}
	return success;
}

/*----------------------------------------select functions--------------------------------*/




class Equals : public Selection{
   Table *tbl;
   void *getTbl() { return tbl; }
   public:
   Equals(Table *t,Buffer *b,Field *f) : tbl(t) {from=b;fld=f;type=EQU;} 
   int getNext(int current,int offset,int);
   Buffer *getBuffer();
   Buffer *giveBuffer(Buffer *);
   int getTotal() {if(getStoreSize()>0) return Selection::getTotal(); else return tbl->getEquals(*from,fld);}
   };

void Selection::cacheSelection()
{
	Table *tbl=(Table*)getTbl();
	if(tbl){
		if(cacheSize>MINCACHESIZE){
			Buffer *fb=0;
			if(from){
				fb=new Buffer(*from,from->getSize());
			}
			Buffer *tb=0;
			if(to){
				tb=new Buffer(*to,to->getSize());
			}
			Selection *s=new Selection(fb,tb,getField(),getType());
			s->putStore(new Buffer(*cache,cacheSize*sizeof(int)));
			tbl->addSelection(s);
		}
	}
}

Buffer* Equals::giveBuffer(Buffer *fromlist)
{
	if(getStoreSize()==0)
		return tbl->getEqualsBuffer(*from,fld,fromlist);
	return Selection::giveBuffer();
}

Buffer* Equals::getBuffer()
{
   if(getStoreSize()==0)
      putStore(tbl->getEqualsBuffer(*from,fld));
   return Selection::getBuffer();
}

int Equals::getNext(int current, int offset,int sp)
{
	int inc;
	if(offset>0){
		inc=1;
	}else{
		inc=-1;
	}
	if(getStoreSize()==0){
		putStore(tbl->getEqualsBuffer(*from,fld));
		cacheSelection();

	}
	if(getStoreSize()){
		return Selection::getNext(current,offset,sp);
	}
	return current;
}



Buffer* Table::getVal(char* val,Field *f)
{
   Buffer *tmp=new Buffer(f->size*elementSize(f->type));
   evaluate(*tmp,val,f);
   return tmp;
}


int Table::getEquals(char* val,Field* f)
{
   int recId=0;
   if(val)
    recId=searchTree(val,f);
   if(recId==0)
      return 0;
   int es=0;
   lock();
   char *tmp=getRecordCached(recId);
   if(tmp){
	   recordInfo* tmpNode=(recordInfo*)(tmp+f->offset);
	   es = tmpNode->centerWeight+1;
   }
   release();
   return es;
}


class uniqueRange : public Selection{
   Table *tbl;
   void *getTbl() { return tbl; }
   public:
   uniqueRange(Table *t,Field *f) : tbl(t){type=UNIQ;setUnique();fld=f;}
   int getNext(int current, int offset,int);
   Buffer *getBuffer();
   Buffer *giveBuffer(Buffer *);
   int getTotal() { if(getStoreSize()>0) return Selection::getTotal(); else return fld->unodes; }
   };



Buffer* uniqueRange::getBuffer()
{
   if(getStoreSize()==0){
      putStore(tbl->getRangeBuffer(0,0,fld,1,fld->unodes));
      cacheSelection();
   }
   return Selection::getBuffer();
}
 


Buffer* uniqueRange::giveBuffer(Buffer *fromlist)
{
   if(getStoreSize()==0){
      putStore(tbl->getRangeBuffer(0,0,fld,1,fld->unodes));
      cacheSelection();
   }
   return Selection::giveBuffer();
}

int uniqueRange::getNext(int current, int offset,int sp)
{
	if(getStoreSize()==0){
		putStore(tbl->getRangeBuffer(0,0,fld,1,fld->unodes));
		cacheSelection();
	}
	return Selection::getNext(current,offset,sp);
}

class Range : public Selection{
   Table *tbl;
   int total;
   int start;
   int end;
   LinkedBuffer *fsort;
   int order;
   void *getTbl() { return tbl; }
   public:
   Range(Table *t,Buffer *b, Buffer *e,Field *f, char typ,int order=0,LinkedBuffer *fs=0);
   int getNext(int current,int offset, int savePos);
   Buffer *getBuffer();
   Buffer *giveBuffer(Buffer *fromlist);
   int getTotal() { return total;}
   };



Buffer* Range::giveBuffer(Buffer *fromlist)
{
	if(getStoreSize()==0){
		putStore(tbl->getRangeBuffer(start,tbl->getLastEqual(end,fld),fld,type&UNIQ,total,order,fsort));
		total=Selection::getTotal();
		if(fsort==0)
			cacheSelection();
	}
	return Selection::giveBuffer();
}



Buffer* Range::getBuffer()
{
   if(getStoreSize()==0){
      putStore(tbl->getRangeBuffer(start,tbl->getLastEqual(end,fld),fld,type&UNIQ,total,order,fsort));
      total=Selection::getTotal();
	  if(fsort==0)
		  cacheSelection();
   }
   return Selection::getBuffer();
}


Range::Range(Table *t,Buffer *b, Buffer *e,Field *f, char typ,int ord,LinkedBuffer *fs)
: tbl(t),total(0),start(0),end(0),fsort(fs),order(ord)
{
   from=b;
   to=e;
   type=typ;
   fld=f;
   char *froms=0;
   if(from)
	   froms=*from;
   char *tos=0;
   if(to)
	   tos=*to;
   total=tbl->getRangeSize(froms,tos,type,fld,&start,&end);
   if(type&UNIQ){
       putStore(tbl->getRangeBuffer(start,end,fld,1,total));
       cacheSelection();
       total=Selection::getTotal();
   }else
	   if(fsort){
		   putStore(tbl->getRangeBuffer(start,end,fld,0,total,order,fsort));
		   total=Selection::getTotal();
	   }
}


int Range::getNext(int current,int offset, int savePos)
{
	if(getStoreSize()==0){
		putStore(tbl->getRangeBuffer(start,tbl->getLastEqual(end,fld),fld,type&UNIQ,total,order,fsort));
		total=Selection::getTotal();
		if(fsort==0)
			cacheSelection();
	}
	return Selection::getNext(current,offset,savePos);
}






void Selection::sort()
{
     if(cacheSize>0 && (cache!=0))
       qsort(*cache,cacheSize,sizeof(int),intcmp);
}


#include "dbms.h"
extern DataBaseManager* dbms;

Selection* Table::selectByRelation(int cid,Field *f,Buffer* query)
{
	Selection* sb=0;
	if(f->type==INDEX_TYPE){
		if(cid){
			Table *t=dbms->selectTable(cid,f->tableName);
			if(t){
				sb=t->getSelection(cid,query);
				query=0;
				if(sb!=0){
					Buffer *mb=sb->giveBuffer();
					delete sb;
					sb=0;
					if(mb!=0){
						int *x=(int*)((char*)*mb);
						int total=mb->getSize()/sizeof(int);
						int st=dbf->getTotal();
						if(st>0){
							Buffer* s=new Buffer(sizeof(int)*st);
							char *ex=*s;
							char *b=ex;
							for(int i=0;i<total;++i){
								Buffer *eb=getEqualsBuffer((char*)(x+i),f);
								if(eb!=0){
									int cs=eb->getSize();
									memcpy(ex,*eb,cs);
									ex+=cs;
									delete eb;
								}
							}
							int n=ex-b;
							if(n>0){
								if(n<s->getSize()){
									Buffer *tmp=new Buffer(*s,n);
									delete s;
									s=tmp;
								}
								sb=new Selection();
								sb->putStore(s);
							}else{
								delete s;
							}
						}
						delete mb;
					}
				}
			}
		}
	}
	delete query;
	return sb;
}


void deleteLinked(LinkedBuffer* &fs)
{
	while(fs){
		LinkedBuffer *t=fs;
		fs=fs->next;
		delete t;
	}
}


int Table::getFieldAny(queryStruct* qx,char* fieldName)
{
	int cid=dbms->openDB(dbname);
	LinkedBuffer *tl=0;
	int rc=0;
	if(getParent(fieldName,cid,tl)){
		rc=1;
		qx->f=((iTable*)(char*)*tl)->f;
		if(tl->next){
			int i=0;
			LinkedBuffer *l=tl;
			for(;l!=0;l=l->next){
				i+=strlen(((iTable*)(char*)*l)->f->fieldName)+1;
			}
			Buffer *b=new Buffer(i);
			qx->rel=b;
			char *c=*b;
			while(1){
				strcpy(c,((iTable*)(char*)*tl)->f->fieldName);
				c+=strlen(c);
				if(tl->next){
					*c++='.';
					l=tl;
					tl=tl->next;
					delete l;
				}else{
					break;
				}
			}
		}
	}
	deleteLinked(tl);
	dbms->closeDB(cid);
	return rc;
}


Selection* Table::madSearch(char* string, Buffer *set,Field* f)
{
	if(set){
		txtSrch *se=new txtSrch(string);
		int *x=(int*)((char*)(*set));
		int total=set->getSize()/sizeof(int);
		int count=0,i=0;
		for(;i<total;++i){
			htmlBuffer *v=getFieldValue(x[i],0,f);
			int found=0;
			while(v){
				if(searchable(v) && se->search(*v,v->getSize())){
					found=1;
					deleteHtmlBuffer(v);
					break;
				}
				htmlBuffer *tmp=v;
				v=v->next;
				delete tmp;
			}
			if(found==0)
				x[i]=0;
			else
				count++;
		}
		if(count<total){
			if(count>0){
				Buffer *nb=new Buffer(count*sizeof(int));
				int *z=(int*)((char*)(*nb));
				int j=0;
				for(i=0;j<count;++i){
					if(x[i]!=0)
						z[j++]=x[i];
				}
				delete set;
				set=nb;
			}else{
				delete set;
				set=0;
			}
		}
		delete se;
		if(set){
			Selection *s=new Selection();
			s->putStore(set);
			return s;
		}
	}
	return 0;
}

//int sid;

char* maskCopy(char*q,Buffer *v)
{
	int l=v->getSize()-1;
	*q++=' ';
	*q++='^';
	for(char*s=*v;l>0;l--){
       *q++=*s++^0xff;
	}
	*q++='"';
	return q;
}

//==================================================================================================================================================


iTable* Table::getParent(char * fieldname,int cid,LinkedBuffer* &tablelist)
{
	LinkedBuffer* tl=tablelist;
	while(tl){
		if(((iTable*)(char*)*tl)->t==this)
			return 0;
		if(tl->next)
			tl=tl->next;
		else
			break;
	}
	LinkedBuffer *nb=new LinkedBuffer(new Buffer(sizeof(iTable)));
	iTable *rt=((iTable*)(char*)*nb);
	rt->t=this;
	if(tl)
		tl->next=nb;
	else
		tablelist=nb;
	Table *t;
	Field *f=getField(fieldname);
	if(f==0){
		rt=0;
		for(int i=0;fieldname[i]!=0;++i){
			if(fieldname[i]=='.'){
				fieldname[i]=0;
				f = getField(fieldname);
				fieldname[i]='.';
				if(f && (f->type==INDEX_TYPE)){
					if((t=dbms->selectTable(cid,f->tableName))!=0){
						rt=t->getParent(fieldname+i+1,cid,tablelist);
					}
				}
				break;
			}
		}
		if(rt==0){
			for(SField *sf=fields;sf!=0;sf=(SField*)f->next){
				f=*sf;
				if(f->type==INDEX_TYPE){
					if((t=dbms->selectTable(cid,f->tableName))!=0){
						if((rt=t->getParent(fieldname,cid,tablelist))!=0){
							break;
						}
					}
				}
			}
		}
	}
	if(rt){
		((iTable*)(char*)*nb)->f=f;
	}else{
		if(tl)
			tl->next=0;
		else
			tablelist=0;
		delete nb;
	}
	return rt;
}



int Table::getRecordNo(LinkedBuffer* tbllist,int rec)
{
	if(rec>0){
		if(tbllist->next==0)
			return rec;
		else{
			lock();
			char *recBuff=getRecordCached(rec);
			if(recBuff){
				int r=*((int*)(recBuff+getFieldOffset(((iTable*)(char*)*tbllist)->f)));
				release();
				return(((iTable*)(char*)*(tbllist->next))->t->getRecordNo(tbllist->next,r));
			}
			release();
		}
	}
	return 0;
}

int Table::compareRecords(int a,int b,Field *f)
{
	lock();
	char *arecBuff=getRecordCached(a);
	char *brecBuff=getRecordCached(b);
	int r=2;
	if(arecBuff && brecBuff && getFieldDim(arecBuff,f) && getFieldDim(brecBuff,f)){
		int of=getFieldOffset(f);
		r=compare(arecBuff+of,brecBuff+of,f->type);
		if(r>0)
			r=1;
		else
			if(r<0)
				r=-1;
	}
	release();
	return r;
}

typedef struct ITEM{
	int value;
	int recordno;
	ITEM *left;
	ITEM *right;
	ITEM *equals;
	short balance;
}Item;


class avlTree : public virtual ThreadSafe{
	enum dir_t { LEFT = -1,RIGHT = 1 };
	// Use mnemonic constants for valid balance-factor values
    enum balance_t { LEFT_HEAVY = -1, BALANCED = 0, RIGHT_HEAVY = 1 };

	enum height_effect_t { HEIGHTNOCHANGE = 0, HEIGHTCHANGE = 1 };
	int order;
	int unique;
	Table *table;
	Buffer *itemBuf;
	int cid;
	LinkedBuffer *tablelist;
	Item *Root;
	Table *mytable;
	Field* myfield;
	int RotateOnce(Item* &root, dir_t dir);
    int RotateTwice(Item* &root, dir_t dir);
	int  ReBalance(Item* &root);
	int Insert(Item* &,Item*,int&);	
	int avlTree::compareItems(Item* a,Item* b);
// Return true if the tree is too heavy on the left side
    inline static int
    LEFT_IMBALANCE(short bal) { return (bal < LEFT_HEAVY); }

// Return true if the tree is too heavy on the right side
    inline static int
    RIGHT_IMBALANCE(short bal) { return (bal > RIGHT_HEAVY); }
public:
	avlTree *next;
	avlTree(char*,Table*,int order,int cid,int unique=0);
	~avlTree() {delete itemBuf;deleteLinked(tablelist);}
	void getRangeAsc(Item *node,int* &m);
	void getRangeDesc(Item *node,int* &m);
	int sortList(int *m,int total);
};

void avlTree::getRangeDesc(Item *node,int*&m)
{ 
	if(node->left)
		getRangeDesc(node->left,m);
	int *p=m;
	for(Item *n=node;n!=0;n=n->equals)
		*m++=n->recordno;
	if(m-p>1){
		if(next)
			next->sortList(p,m-p);
		else{
			if(order){
				for(int *e=m,*b=p;b<e;b++){
					e--;
					int t=*b;
					*b=*e;
					*e=t;
				}
			}
		}
	}
	if(node->right)
		getRangeDesc(node->right,m);
}


void avlTree::getRangeAsc(Item *node,int*&m)
{ 
	if(node->right)
		getRangeAsc(node->right,m);
	int *p=m;
	for(Item *n=node;n!=0;n=n->equals){
		*m++=n->recordno;
	}
	if(m-p>1){
		if(next)
			next->sortList(p,m-p);
		else{
			if(order==0){
				for(int *e=m,*b=p;b<e;b++){
					e--;
					int t=*b;
					*b=*e;
					*e=t;
				}
			}
		}
	}
	if(node->left)
		getRangeAsc(node->left,m);
}

class vTable : public virtual ThreadSafe{
	avlTree *vtree;
	int *list;
	int total;

public:
	vTable(LinkedBuffer* fs,Table *t,int *,int,int cid);
	int sort() { return vtree->sortList(list,total);}
	~vTable(){while(vtree){ avlTree *ltree=vtree->next;delete vtree;vtree=ltree;}}
};

vTable::vTable(LinkedBuffer *fs,Table *t,int *m,int n,int cid)
:vtree(0),list(m),total(n)
{
	avlTree* ltree=0;
	while(fs){
		avlTree *v=new avlTree(*fs,t,fs->getType(),cid);
		if(ltree)
			ltree->next=v;
		else
			vtree=v;
		ltree=v;
		fs=fs->next;
	}
}




avlTree::avlTree(char* fieldNames,Table *t,int sortorder,int cd,int uniq)
:unique(uniq),order(sortorder),table(t),itemBuf(0),cid(cd),tablelist(0),next(0)
{	
	iTable *rt=table->getParent(fieldNames,cid,tablelist);
	if(rt){
		mytable=rt->t;
		myfield=rt->f;
	}else{
		mytable=0;
		myfield=0;
	}
}

int avlTree::sortList(int *m,int total)
{
	if(mytable && myfield){
		delete itemBuf;
		Root=0;
		itemBuf=new Buffer(sizeof(Item)*total);
		Item *x=(Item*)((char*)*itemBuf);
		memset(x,0,itemBuf->getSize());
		int change=0;
		if(mytable==table){
			for(int i=0;i<total;++i){
insertThis0:
				if(m[i]>0){
					x->recordno=m[i];
					x->value=x->recordno;
					if(Insert(Root,x,change)>=0){
						x++;
					}
				}else{
					if(--total>i){
						m[i]=m[total];
						m[total]=0;
						goto insertThis0;
					}
				}
			}
		}else{
			for(int i=0;i<total;++i){
insertThis:
				int v=m[i];
				if(m[i]>0){
					x->value=table->getRecordNo(tablelist,v);
				}
				if(x->value>0){
					x->recordno=v;
					if(Insert(Root,x,change)>=0)
						x++;
				}
				else{
					if(--total>i){
						m[i]=m[total];
						m[total]=v;
						goto insertThis;
					}
				}
			}
		}
		if(Root!=0){
			int *p=m;
			if(order)
				getRangeDesc(Root,m);
			else
				getRangeAsc(Root,m);
			return m-p;
		}
	}
	return 0;
}


int  avlTree::RotateOnce(Item* &root, dir_t dir)
{
	Item * oldRoot = root; 
	int  heightChange;
	if(dir==LEFT){
		if(root->right->balance == 0)
			heightChange=HEIGHTNOCHANGE;
		else
			heightChange=HEIGHTCHANGE;
		root = oldRoot->right;
		oldRoot->right = root->left;
		root->left=oldRoot;
		oldRoot->balance = -(--(root->balance));
	}else{
		if(root->left->balance == 0)
			heightChange=HEIGHTNOCHANGE;
		else
			heightChange=HEIGHTCHANGE;
		root = oldRoot->left;
		oldRoot->left = root->right;
		root->right=oldRoot;
		oldRoot->balance =-(++(root->balance));
	}
	return  heightChange;
}

int avlTree::RotateTwice(Item* &root, dir_t dir)
{
	Item* oldRoot = root;
	Item * oldOtherDirSubtree;
	if(dir==LEFT){
        oldOtherDirSubtree= root->right;
        root = oldRoot->right->left;
        oldRoot->right = root->left;
        root->left = oldRoot;
        oldOtherDirSubtree->left = root->right;
        root->right = oldOtherDirSubtree;
	}
	else{
        oldOtherDirSubtree= root->left;
        root = oldRoot->left->right;
        oldRoot->left = root->right;
        root->right = oldRoot;
        oldOtherDirSubtree->right = root->left;
        root->left = oldOtherDirSubtree;
	}
	if (root->balance>0){
		root->left->balance = -root->balance;
		root->right->balance = 0; 
	}else{
		root->right->balance = -root->balance;
		root->left->balance  = 0;
	}
	root->balance = 0;
	return  HEIGHTCHANGE;
}


// Rebalance -- static member function to rebalance a (sub)tree
//              if it has become imbalanced.
//              Return 1 if the tree height changes due to rotation,
//              otherwise return 0.
int  avlTree::ReBalance(Item* &root)
{
	int  heightChange = HEIGHTNOCHANGE;
	
	if (LEFT_IMBALANCE(root->balance)) {
		// Need a right rotation
		if (root->left->balance  ==  RIGHT_HEAVY) {
			// RL rotation needed
            heightChange = RotateTwice(root, RIGHT);
		} else {
			// RR rotation needed
            heightChange = RotateOnce(root, RIGHT);
		}
	} else if (RIGHT_IMBALANCE(root->balance)) {
		// Need a left rotation
		if (root->right->balance  ==  LEFT_HEAVY) {
			// LR rotation needed
            heightChange = RotateTwice(root, LEFT);
		} else {
			// LL rotation needed
            heightChange = RotateOnce(root, LEFT);
		}
	}
	
	return  heightChange;
}


int avlTree::compareItems(Item* a,Item* b)
{
	return mytable->compareRecords(a->value,b->value,myfield);
}


int avlTree::Insert(Item*  &root,Item* item, int &change)
{
	
	// See if the tree is empty
	if (root == 0){
		if(mytable->exists(item->value)){
			// Insert new node here 
			root = item;
			change =  HEIGHTCHANGE;
			return  1;
		}
		return -1;
	}  
	// Initialize
	int  increase = 0;
	
	// Compare items and determine which direction to search
	switch(compareItems(root,item)){
	case	-1:
		if(Insert(root->left, item, change)>0){
			increase=-1*change;
		}
		break;
	case	1:
		if(Insert(root->right, item, change)>0){
			increase=change;
		}
		break;
	case	0:
		if(unique==0){
			int r=item->recordno;
			int v=item->value;
			item->recordno=root->recordno;
			item->value=root->value;
			item->equals=root->equals;
			root->equals=item;
			root->recordno=r;
			root->value=v;
			return 0;
		}
	default:
		return -1;
	}
	root->balance += increase;    // update balance factor 
	
	// --------------------------------------------------------------------
	// re-balance if needed -- height of current tree increases only if its
	// subtree height increases and the current tree needs no rotation.
	// --------------------------------------------------------------------
	if(increase && root->balance)
		change=(1 - ReBalance(root));
	else
		change = HEIGHTNOCHANGE;
	return  1;
}











//==================================================================================================================================================

Selection* Table::getUnique(queryStruct *qx ,Buffer* subset,int total)
{
	if(subset==0 && qx->rel==0){
		Buffer *b;
		if((b=getSelectionFromCache(qx->f,UNIQ,0,0))!=0){
			Selection *s=new Selection();
			s->putStore(b);
			return s;
		}else
			return new uniqueRange(this,qx->f);
	}
	char *fieldname=0;
	if(qx->rel){
		fieldname=*(qx->rel);
	}else{
		if(qx->f){
			fieldname=qx->f->fieldName;
		}
	}
	if(fieldname){
		Buffer *m=0;
		if(subset==0){
			m=dbf->getValidList();
		}else{
			m=subset;
			subset=0;
		}
		if(total==0)
			total=m->getSize()/sizeof(int);
		int cid=dbms->openDB(dbname);
		avlTree* vtree=new avlTree(fieldname,this,0,cid,1);
		int n=vtree->sortList((int*)(char*)*m,total);
		delete vtree;
		m->setSize(n*sizeof(int));
		dbms->closeDB(cid);
		Selection *s=new Selection();
		s->putStore(m);
		qx->f=0;
		return s;
	}
	return 0;
}

Selection* Table::Sort(LinkedBuffer* &fs,Buffer* &subset)
{
	Selection *s=0;
	if(fs){
		Buffer *m=0;
		if(subset==0)
			m=dbf->getValidList();
		else{
			m=subset;
			subset=0;
		}
		if(m){
			int *list=(int*)((char*)*m);
			int cid=dbms->openDB(dbname);
			vTable *vt=new vTable(fs,this,list,m->getSize()/sizeof(int),cid);
			m->setSize(vt->sort()*sizeof(int));
			delete vt;
			s=new Selection();
			s->putStore(m);
			dbms->closeDB(cid);
			deleteLinked(fs);
			fs=0;
		}
	}
	return s;
}

char *ascdesc[]={"asc","desc"};

Selection* Table::getSelection(int cid,Buffer* query,Buffer* subset,int addsubset)
{
	queryStruct* qx;
	LinkedBuffer *fs=0;
	Buffer* qbuff=getQueryList(query,fs);
	int ts=0;
	if(qbuff){
		qx=(queryStruct*) ((char*)*qbuff);
		ts=qbuff->getSize()/sizeof(queryStruct) - 1;
	}
	if((qbuff==0) || ((qx[0].m==INCLUDE_ALL) && (ts==1) && (qx[1].f==0))){
		delete qbuff;
		deleteLinked(fs);
		if(subset){
			Selection *s=new Selection();
			s->putStore(subset);
			return s;
		}
		if(qbuff){
			return ALLSELECTED;
		}else{
			return 0;
		}
	}
	Buffer *b;
	int qi=0;
	int sin=0;
	Selection  *selections[128];
	memset(selections,0,sizeof(selections));
	int alt=-1;
	int sortby=-1;
	int selectunique=-1;
	int likes=0;
	LinkedBuffer *fstmp=fs;
	if(fstmp && qx[ts].f){
		Table *prnt;
		if(qx[ts].f->type!=INDEX_TYPE || qx[ts].rel==0){
			prnt=this;
		}
		else{
			prnt=dbms->selectTable(cid,qx[ts].f->tableName);
		}
		while(fstmp){
			LinkedBuffer *tablelist=0;
			iTable *rt=getParent(*fstmp,cid,tablelist);
			if((rt==0) || (rt->t!=prnt)){
				deleteLinked(tablelist);
				break;
			}
			deleteLinked(tablelist);
			fstmp=fstmp->next;
		}
		if(fstmp==0){ // fs is as usual,fstmp is the first field in sorting hierarchy,fs the rest;if fstmp true then sorting needed from single table
			fstmp=fs;
			fs=fstmp->next;
		}else
			fstmp=0;
	}
	if(qx[0].m & INCLUDE_ALL){
		if(qx[1].f){
			Selection *s =0;
			if((fs==0) && (qx[ts].rel==0)){
				Buffer *b=getSelectionFromCache(qx[1].f,FROMTO,0,0);
				if(b!=0){
					s=new Selection();
					s->putStore(b);
					qx[1].f=0;
					delete fstmp;
					fstmp=0;
				}
			}
			if(s==0){
				//		if small subset or multitable sort(fstmp==0) exists, then use avltree for sort
				if((fstmp==0) || (subset && ((int)(subset->getSize()/sizeof(int))<getTotal()/4))){
					if(fstmp){
						fs=fstmp;
						fstmp=0;
					}
					s=Sort(fs,subset);
				}else{
					if(qx[1].f->type==INDEX_TYPE && qx[1].rel){
						int l=0;
						delete fstmp;
						fstmp=fs;
						while(fstmp){
							l+=fstmp->getSize()+5;
							fstmp=fstmp->next;
						}
						int bl;
						Buffer *buff=new Buffer(bl=(qx[1].rel->getSize()+12+l));
						char *biff=*buff;
						int la=snprintf(biff,bl-1,"order by %s",(char*)*(qx[1].rel));
						if(l>0){
							l=la;
							while(fs){
								char *s=*fs;
								while(*s){
									if(*(s++)=='.')
										break;
								}
								if(*s==0)
									s=*fs;
								l+=snprintf(biff+l,bl-l,",%s %s",s,ascdesc[fs->getType()]);
								fstmp=fs->next;
								delete fs;
								fs=fstmp;
							}
						}
						buff->setSize(l+1);
						s=selectByRelation(cid,qx[1].f,buff);
					}else{
						if(fs){
							int order=0;
							if(qx[1].m&ORDER){
								order=-1;
							}else{
								order=1;
							}						
							s=new Range(this,0,0,qx[1].f,FROMTO,order,fs);
							deleteLinked(fs);
							delete fstmp;
							fstmp=0;
						}else{
							Buffer *b=getSelectionFromCache(qx[1].f,FROMTO,0,0);
							if(b==0)
								s=new Range(this,0,0,qx[1].f,FROMTO,0,0);
							else{
								s=new Selection();
								s->putStore(b);
							}
							delete fstmp;
							fstmp=0;
						}
					}
					qx[1].f=0;
				}
			}
			if(subset==0 || s==0){
				if(s!=0){
					if(s->getTotal()>0){
						if(sortby==-1){
							if(qx[1].m&ORDER){
								s->setOrder(-1);
							}else{
								s->setOrder(1);
							}
						}
					}else{
						delete s;
						s=0;
					}
				}
				delete qx[ts].rel;
				deleteLinked(fs);
				delete fstmp;
				delete qbuff;
				return s;
			}else{
				selections[0]=s;
				sortby=0;
				sin=1;
			}
		}else{
			deleteLinked(fs);
			delete fstmp;
			delete qx[ts].rel;
			delete qbuff;
            if((subset!=0) && subset->getSize()>0){
				Selection *s=new Selection();
				s->putStore(subset);
				if(qx[1].m&ORDER){
					s->setOrder(-1);
				}else{
					s->setOrder(1);
				}
				return s;
			}else{
				delete subset;
				return 0;
			}
		}
	}else{
		for(qi=0;qi<ts;++qi){
			if(qx[qi].f!=0){
				if(qx[qi].rel!=0 && ((qx[qi].m&UNIQ)==0)){// what is value of m for 'is unique'?
					if(qx[qi].f && qx[qi].f->type==INDEX_TYPE){
						Buffer *nqb=new Buffer(2048);
						char *nq=*nqb;
						char *b=nq;
						char* ref=nq+nqb->getSize();
						nq+=snprintf(nq,ref-nq,"where %s %s",(char*)*qx[qi].rel,getstring(qx[qi].m));
						if(qx[qi].v){
							nq=maskCopy(nq,qx[qi].v);
							delete qx[qi].v;
						}
						delete qx[qi].rel;
						qx[qi].rel=0;
						for(int i=qi+1;i<ts;++i){
							if((qx[qi].f==qx[i].f) && (qx[i].rel!=0) && ((qx[i].m&UNIQ)==0)){
								char *andor="or";
								if(qx[ts].m&AND){
									andor="and";
								}
								nq+=snprintf(nq,ref-nq," %s %s %s",andor,(char*)*qx[i].rel,getstring(qx[i].m));
								if(qx[i].v){
									nq=maskCopy(nq,qx[i].v);
									
								}
								qx[i].f=0;
								delete qx[i].v;
								delete qx[i].rel;
								qx[i].rel=0;
							}
						}
						if((fstmp!=0) && ((ts==1) || (qx[ts].m&AND)) && (qx[ts].f==qx[qi].f) && (qx[ts].rel!=0)){
							delete fstmp;
							fstmp=0;
							nq+=snprintf(nq,ref-nq," order by %s",(char*)*(qx[ts].rel));
							while(fs){
								char *s=*fs;
								while(*s){
									if(*(s++)=='.')
										break;
								}
								if(*s==0)
									s=*fs;								
								nq+=snprintf(nq,ref-nq,",%s %s",s,ascdesc[fs->getType()]);
								fstmp=fs->next;
								delete fs;
								fs=fstmp;
							}
							sortby=sin;
							qx[ts].f=0;
							delete qx[ts].rel;
							qx[ts].rel=0;
						}
						nqb->setSize((nq-(char*)*nqb)+1);
						selections[sin]=selectByRelation(cid,qx[qi].f,nqb);
						if(selections[sin]==0){
							selections[sin]=new Selection();
						}
						sin++;
						qx[qi].f=0;
					}
				}else{
					Buffer *from=0;
					if(qx[qi].m!=LIKE && qx[qi].m!=LIKES){
						if(qx[qi].v){
							from=getVal(*qx[qi].v,qx[qi].f);
							delete qx[qi].v;
							qx[qi].v=0;
						}else{
							from=0;
						}
					}
					else{
						if(qx[qi].m==LIKE){
							from=qx[qi].v;
							qx[qi].v=0;
						}
					}
					Buffer* to=0;
					if(qx[qi].to){
						to=getVal(*qx[qi].to,qx[qi].f);
					}
					delete qx[qi].to;
					switch(qx[qi].m&~(EXCLUDE|UNIQ)){
					case LIKES:
						likes++;
						break;
					case LIKE:
						{	
							selections[sin]=new Selection();
							char tmp[64];
							if(qx[qi].f){
								snprintf(tmp,64,"%s.%s.%s",dbname,tableName,qx[qi].f->fieldName);
								Buffer *likes=findWord(*from,tmp);
								if(likes){
									selections[sin]->putStore(likes);
									if(alt<0)
										alt=sin;
								}
							}
							sin++;
						}
						qx[qi].f=0;
						break;
					case EQU:
						delete to;
						if(stricmp(*from,"null")==0){
							delete from;
							if((b=getSelectionFromCache(qx[qi].f,FROMTO,0,0))!=0){
								Selection *s=new Selection();
								s->putStore(b);
								selections[sin]=s;
							}
							if(selections[sin]==0)
								selections[sin]=new Range(this,0,0,qx[qi].f,FROMTO,0,0);
							qx[qi].m^=EXCLUDE;
						}else{
							if((b=getSelectionFromCache(qx[qi].f,EQU,*from,0))!=0){
								delete from;
								Selection *s=new Selection();
								s->putStore(b);
								selections[sin]=s;
							}
							if(selections[sin]==0)
								selections[sin]=new Equals(this,from,qx[qi].f);
						}

						if(qx[qi].m&EXCLUDE){
excludeSelected:
							Buffer *mx=selections[sin]->giveBuffer();
							Buffer *eb;
							int *x;
							int at;
							if(subset && !addsubset){
								eb=new Buffer(*subset,subset->getSize());
								x=(int*)((char*)(*eb));
								at=eb->getSize()/sizeof(int);
							}
							else{
								if(qx[qi].m&UNIQ){
									Selection *u=new uniqueRange(this,qx[qi].f);
									eb=u->giveBuffer();
									x=(int*)((char*)(*eb));
									at=eb->getSize()/sizeof(int);
									delete u;
								}else{
									eb=dbf->getValidList();
									x=(int*)((char*)(*eb));
									x++;
									at=(eb->getSize()/sizeof(int))-1;
								}
							}
							if(at>0){
								if((mx!=0) && (mx->getSize()>0)){
									sortList(mx);
									int mj=0;
									for(int mi=0;mi<at;++mi){
										if(findinList(mx,x[mi])==0){
											x[mj++]=x[mi];
										}
									}
									Buffer *all=eb;
									if(mj){
										eb=new Buffer((char*)x,mj*sizeof(int));
									}else{
										eb=0;
									}
									delete all;
									delete mx;
								}
							}else{
								delete eb;
								eb=0;
							}
							delete selections[sin];
							selections[sin]=new Selection();
							if(eb)
								selections[sin]->putStore(eb);
						}
						sin++;
						if(qx[qi].m&UNIQ)
							selectunique=qi;
						break;
					case 0:
						delete from;
						delete to;
						selectunique=qi;
						break;
						/*
						if((b=getSelectionFromCache(qx[qi].f,UNIQ,0,0))!=0){
							Selection *s=new Selection();
							s->setField(qx[qi].f);
							s->putStore(b);
							selections[sin]=s;
						}
						if(selections[sin]==0)
							selections[sin]=new uniqueRange(this,qx[qi].f);
						selections[sin]->setUnique();
						sin++;
						*/
						break;
					case LTE:
						qx[qi].m|=INCLUDE_TO;
					case LT:
						delete to;
						to=from;
						from=0;
						qx[qi].m&=(EXCLUDE|UNIQ|INCLUDE_TO);
						goto rangeSelect;
					case GTE:
						qx[qi].m|=INCLUDE_FROM;
					case GT:
						qx[qi].m&=(EXCLUDE|UNIQ|INCLUDE_FROM);
						delete to;
						to=0;
					case FROMTO+INCLUDE_FROM:
					case FROMTO+INCLUDE_TO:
					case FROMTO+INCLUDE_FROM+INCLUDE_TO:
					case FROMTO:
rangeSelect:
						int sorthere=-1;
						if((qx[ts].m&AND) && (qx[ts].f==qx[qi].f) && (qx[ts].rel==0)){
							if(fstmp){
								if(fs){
									sorthere=1;
								}
								else
									sorthere=0;
							}else
								sorthere=2;
						}
						qx[qi].m|=FROMTO;
						if(sorthere<=0){
							char *froms=0;
							if(from)
								froms=*from;
							char *tos=0;
							if(to)
								tos=*to;
							if((b=getSelectionFromCache(qx[qi].f,(char)qx[qi].m,froms,tos))!=0){
								if(sorthere==0){
									sortby=sin;
								}
								Selection *s=new Selection();
								s->putStore(b);
								selections[sin]=s;
								delete from;
								delete to;
							}
						}
						int flags=qx[qi].m&~EXCLUDE;

						if(subset || ts>1){
							flags&=~UNIQ;
						}
						if(selections[sin]==0){
							selections[sin]=new Range(this,from,to,qx[qi].f,flags);
							if((qx[qi].m&EXCLUDE)==0){
								if(sorthere==0){
									sortby=sin;
								}else{
									if((sorthere==1) && (addsubset==0) && (qx[ts].m&AND) && (ts<3) && (selections[sin]->getTotal()>getTotal()/4) ){
										sortby=sin;
										int order;
										if(qx[ts].m&ORDER){
											order=-1;
										}else{
											order=1;
										}
										delete selections[sin];
										selections[sin]=new Range(this,from,to,qx[qi].f,flags,order,fs);
										deleteLinked(fs);
									}
								}
							}
						}
						if(qx[qi].m&EXCLUDE){
							goto excludeSelected;
						}
						if(sortby==sin){
							if((qx[ts].m&AND) && (addsubset==0)){
								delete fstmp;
								fstmp=0;
								qx[ts].f=0;
							}else{
								sortby=-1;
							}
						}
						if(qx[qi].m&UNIQ){
							if(sortby==-1 && fs==fstmp)
								sortby=sin;
							if((flags&UNIQ)==0)
								selections[sin]->setUnique();
							selectunique=qi;
						}
						sin++;
				}
			}
		}
	  }
   }
   if(qi==0){
	   if(subset==0){
		   delete qx[ts].rel;
		   deleteLinked(fs);
		   delete fstmp;
		   delete qbuff;
		   return 0;
	   }
   }
   if(sortby==-1 && fs==fstmp)
	   sortby=alt;
   if(addsubset==0 && sin==0 && likes==0 && selectunique!=-1){
	   selections[sin++]=getUnique(&qx[selectunique],subset);
	   subset=0;
	   if(sortby==-1 && fs==fstmp)
		   sortby=0;
	   selectunique=-1;
   }
   Selection *ns=0;
   if(sin==1 && likes==0){
	   if(subset==0){
		   if(selections[0]->isUnique()==0 && (selectunique!=-1)){
			   if(sortby==-1 && fs==fstmp)
				   sortby=0;
			   Buffer *m=selections[0]->giveBuffer();
			   delete selections[0];
			   if(m){
				   if(qx[selectunique].f==qx[ts].f){
					   if(fstmp){
						   deleteLinked(fs);
						   delete fstmp;
						   fstmp=0;
						   sortby=0;
					   }
				   }
				   selections[0]=getUnique(&qx[selectunique],m);
			   }
			   else
				   selections[0]=0;
		   }
		   if(selections[0] && selections[0]->getTotal()>0){
			   if(fstmp==0){
				   ns=selections[0];
				   if(fs){
					   Buffer *m=ns->giveBuffer();
					   delete ns;
					   ns=Sort(fs,m);   
				   }else{
					   if (sortby==-1)
						   ns->sort();
				   }
				   if(qx[ts].m&ORDER){
					   ns->setOrder(-1);
				   }else{
					   ns->setOrder(1);
				   }
				   delete qx[ts].rel;
				   delete qbuff;
				   return ns;
			   }else{
				   qx[ts].m|=AND;
			   }
		   }else{
			   delete selections[0];
			   delete fstmp;
			   deleteLinked(fs);
			   delete qx[ts].rel;
			   delete qbuff;
			   return 0;
		   }
	   }else{
		   if(addsubset==0){
			   selections[sin]=new Selection();
			   selections[sin]->putStore(subset);
			   subset=0;
			   if(sortby==-1 && (fstmp==fs))
				   sortby=sin;
			   sin++;
			   qx[ts].m|=AND;
		   }
	   }
   }
   if((qx[ts].m&AND)==0){
	   if(addsubset && subset){
		   selections[sin]=new Selection();
		   selections[sin++]->putStore(subset);
		   subset=0;
	   }
   	   int totl=0;
	   int items=0;
	   int *sl=0;
	   Buffer* ms=0;
	   if(likes){
		   for(int i=0;i<ts;++i){
			   if(qx[i].m==LIKES && qx[i].f!=0 && qx[i].v!=0){
				   Buffer *m=0;
				   if(subset==0)
					   m=dbf->getValidList();
				   else
					   m=new Buffer(*subset,subset->getSize());
				   selections[sin]=madSearch(*qx[i].v,m,qx[i].f);
				   if(selections[sin]!=0)
					   sin++;
				   delete qx[i].v;
				   qx[i].f=0;
				   qx[i].v=0;
			   }
		   }
	   }
	   if(qx[ts].f!=0){
		   sortby=0;
		   if((fstmp!=0) && (qx[ts].f->type==INDEX_TYPE) && qx[ts].rel!=0){
			   delete fstmp;
			   int l=0;
			   for(fstmp=fs;fstmp!=0;fstmp=fstmp->next)
				   l+=fstmp->getSize()+5;			   
			   Buffer *nq=new Buffer(l=(qx[ts].rel->getSize()+12+l));
			   char *nqb=*nq;
			   int n=snprintf(nqb,l-1,"order by %s",(char*)*qx[ts].rel);
			   while(fs){
				   char *s=*fs;
				   while(*s){
					   if(*(s++)=='.')
						   break;
				   }
				   if(*s==0)
					   s=*fs;										   
				   n+=snprintf(nqb+n,l-n,",%s %s",(char*)*s,ascdesc[fs->getType()]);
				   fstmp=fs->next;
				   delete fs;
				   fs=fstmp;
			   }
			   nq->setSize(n+1);			   
			   Selection *star=selectByRelation(cid,qx[ts].f,nq);
			   if(star){
				   ms=star->giveBuffer();
				   delete star;
			   }
		   }else{
			   if (fs==0){
				   ms=getSelectionFromCache(qx[ts].f,FROMTO,0,0);
			   }
			   if(ms==0){
				   int order=0;
				   if(fstmp){
					   delete fstmp;
					   fstmp=0;
					   if(fs){
						   if(qx[ts].m&ORDER){
							   order=-1;
						   }else{
							   order=1;
						   }
					   }
					   Selection* star=new Range(this,0,0,qx[ts].f,FROMTO,order,fs);
					   deleteLinked(fs);
					   if(star){
						   ms=star->giveBuffer();
						   delete star;
					   }
				   }
			   }
		   }
	   }else{
		   if(subset){
			   ms=subset;
			   subset=0;
		   }
	   }
	   numList *nl=new numList(256);
	   int k;
	   for(k=0;k<sin;++k){
		   if(selections[k]){
			   if(selections[k]){
				   Buffer *m=selections[k]->giveBuffer();
				   delete selections[k];
				   if(m){
					   int *x=(int*)((char*)*m);
					   int bs=m->getSize()/sizeof(int);
					   for(int j=0;j<bs;++j){
						   int pos;
						   if(nl->getPos(x[j],&pos)==0){
							   nl->insert(pos,x[j]);
						   }
					   }
					   delete m;
				   }
				   selections[k]=0;
			   }
		   }
	   }
	   Buffer *m=0;
	   items=nl->getSize();
	   if(items>0){
		   m = new Buffer(items);
		   memcpy(*m,(int*)*nl,items);
		   items/=sizeof(int);
	   }
	   delete nl;
	   if(ms==0){
		   ns=new Selection();
		   ns->putStore(m);
	   }else{
		   items=0;
		   if(m==0){
			   delete subset;
			   subset=0;
		   }else{
			   sl=(int*)((char*)*ms);
			   totl=ms->getSize()/sizeof(int);
			   if(subset){
				   sortList(subset);
				   for(int j=0;j<totl;++j)
					   if(findinList(subset,sl[j])==0)
						   sl[j]=0;
					   delete subset;
			   }
			   for(k=0;k<totl;++k){
				   if(sl[k]){
					   if(findinList(m,sl[k])){
						   items++;
					   }
					   else
						   sl[k]=0;
				   }
			   }
			   delete m;
			   if(items){
				   m=new Buffer(sizeof(int)*items);
				   int *x=(int*)((char*)*m);
				   for(int n=0,k=0;n<items;k++){
					   if(sl[k])
						   x[n++]=sl[k];
				   }
				   ns=new Selection();
				   ns->putStore(m);
			   }
		   }
		   delete ms;
	   }      
	   if(ns && ns->getTotal()>0){
		   if (selectunique!=-1){
			   Buffer *m=ns->giveBuffer();
			   delete ns;
			   ns=getUnique(&qx[selectunique],m);
			   sortby=selectunique;
		   }
		   if(ns){
			   if(fstmp!=fs){
				   if(fstmp){
					   fs=fstmp;
					   fstmp=0;
				   }
				   Buffer *m=ns->giveBuffer();
				   delete ns;
				   ns=Sort(fs,m);
			   }else{
				   if (sortby==-1)
					   ns->sort();
			   }
			   if(qx[ts].m&ORDER){
				   ns->setOrder(-1);
			   }else{
				   ns->setOrder(1);
			   }
			   
		   }
	   }
	   delete qx[ts].rel;
	   delete fstmp;
	   deleteLinked(fs);
	   delete qbuff;
	   if(ns){
		   if(ns->getTotal()==0){
			   delete ns;
			   ns=0;
		   }
	   }
	   return ns;
   }
   if(subset && (addsubset==0)){
	   selections[sin]=new Selection();
	   selections[sin]->putStore(subset);
	   subset=0;
	   if(sortby==-1 && fs==fstmp)
		   sortby=sin;
	   sin++;
   }
   if(qx[ts].f && (selectunique==-1) && (addsubset==0)){
	   if(fs==0){
		   if(qx[ts].f->type==INDEX_TYPE && qx[ts].rel!=0){
			   int l;
			   Buffer *nqb=new Buffer(l=(qx[ts].rel->getSize()+12));
			   char *nq=*nqb;
			   l=snprintf(*nqb,l+1,"order by %s",(char*)*qx[ts].rel);
			   nqb->setSize(l+1);
			   selections[sin]=selectByRelation(cid,qx[ts].f,nqb);
			   if(selections[sin]){
				   sortby=sin;
				   sin++;
			   }
		   }else{
			   if(fs==0){
				   if((b=getSelectionFromCache(qx[ts].f,FROMTO,0,0))!=0){
					   Selection *s=new Selection();
					   s->putStore(b);
					   selections[sin]=s;
				   }else{
					   selections[sin]=new Range(this,0,0,qx[ts].f,FROMTO);
				   }
			   }
			   if(selections[sin]){
				   sortby=sin;
				   sin++;
			   }
		   }
		   delete fstmp;
		   fstmp=0;
	   }
   }
   int min=sortby;
   if(min==-1 || selections[min]==0){
	   min=0;
	   for(int j=0;j<sin;++j)
		   if(selections[j] && ((selections[min]==0) || selections[j]->getTotal()<selections[min]->getTotal()))
			   min=j;
   }
   if(selections[min]!=0){
	   Buffer *slb=selections[min]->giveBuffer();
	   delete selections[min];
	   selections[min]=0;
	   if(slb!=0){
		   int *sl=(int*)((char*)*slb);
		   int totl;
		   while((totl=slb->getSize()/sizeof(int))>0){
			   int z=-1;
			   for(int j=0;j<sin;++j){
				   if(selections[j]!=0){
					   if((z==-1) || (selections[j]->getTotal()<selections[z]->getTotal()))
						   z=j;
				   }
			   }
			   if(z==-1){
				   ns=new Selection();
				   ns->putStore(slb);
				   slb=0;
				   break;
			   }
			   Buffer* m=selections[z]->giveBuffer(slb);
			   delete selections[z];
			   selections[z]=0;
			   if(m){
				   if(m!=slb){
					   int l=0;
					   sortList(m);
					   int y=m->getSize()/sizeof(int);
					   for(int n=0;l<y && n<totl;++n){
						   if(findinList(m,sl[n])){
							   if(l<n)
								   sl[l]=sl[n];
							   l++;
						   }
					   }
					   slb->setSize(l*sizeof(int));
					   delete m;
				   }
			   }else{
				   break;
			   }
		   }
		   delete slb;
	   }
   }
   int j;
   for(j=0;j<sin;++j)
	   delete selections[j];
   if(likes){
	   if(ns==0 && sin==0){
		   ns=new Selection();
		   ns->putStore(dbf->getValidList());
	   }
	   for(j=0;j<ts;++j){
		   if(qx[j].m==LIKES && qx[j].f!=0 && qx[j].v!=0){
			   if(ns){
				   Buffer *m=ns->giveBuffer();
				   delete ns;
				   ns=madSearch(*qx[j].v,m,qx[j].f);
			   }
			   delete qx[j].v;
		   }
	   }
   }
   if(subset && addsubset){
	   if(ns){
		   Buffer* ms=ns->giveBuffer();
		   if(subset->getSize()>ms->getSize()){
			   Buffer *ts=ms;
			   ms=subset;
			   subset=ts;
		   }
		   sortList(ms);
		   int *sl=(int*)((char*)*ms);
		   int totl=ms->getSize()/sizeof(int);
		   numList *nl=new numList(sl,totl);
		   sl=(int*)((char*)*subset);
		   totl=subset->getSize()/sizeof(int);
		   int pos;
		   for(j=0;j<totl;++j){
			   if(nl->getPos(sl[j],&pos)==0){
				   nl->insert(pos,sl[j]);
			   }
		   }
		   delete ms;
		   delete subset;
		   Buffer *m=0;
		   totl=nl->getSize();
		   if(totl>0){
			   m = new Buffer(totl);
			   memcpy(*m,(int*)(*nl),totl);
		   }
		   delete nl;
		   ns->putStore(m);
	   }else{
		   ns=new Selection();
		   ns->putStore(subset);
	   }
   }
   if(ns && selectunique!=-1){
	   Buffer *m=ns->giveBuffer();
	   delete ns;
	   ns=getUnique(&qx[selectunique],m);
	   sortby=0;
   }
   /*
   {
	   if(su!=0){		   
		   getUnique(su->getField()->fieldName,slb,totl);
		   m=slb;
		   slb=0;
		   Field* fu=su->getField();
		   numList *nl=new numList(128);
		   m=new Buffer(totl*sizeof(int));
		   int *us=(int*)((char*)*m);
		   int fo=getFieldOffset(fu);
		   int j=0;
		   for(int k=0;k<totl;++k){
			   char *tmp=getRecordCached(sl[k]);
			   if(tmp!=0){
				   int v=searchTree(tmp+fo,fu);
				   if(v!=0){
					   int pos;
					   if(nl->getPos(v,&pos)==0){
						   nl->insert(pos,v);
						   us[j++]=sl[k];
					   }
				   }
			   }
		   }
		   delete nl;
		   m->setSize(j*sizeof(int));
	   }
   }
   */
   if(ns){
	   if(ns->getTotal()>0){
		   if(fstmp!=fs){
			   if(fstmp){
				   fs=fstmp;
				   fstmp=0;
			   }
			   Buffer *m=ns->giveBuffer();
			   delete ns;
			   ns=Sort(fs,m);
		   }else{
			   if(sortby==-1){
				   Buffer *m=ns->giveBuffer();
				   sortList(m);
				   ns->putStore(m);
			   }
		   }
		   if(qx[ts].m&ORDER){
			   ns->setOrder(-1);
		   }else{
			   ns->setOrder(1);
		   }
		   
	   }else{
		   delete ns;
		   ns=0;
	   }
   }
   delete qx[ts].rel;
   delete fstmp;
   deleteLinked(fs);
   delete qbuff;
   return ns;
}

inline int matchValues(char* v1,char* v2,int type)
{
	if(type==Table::CHAR_TYPE)
		return stricmp(v1,v2);
	else{
		if(type==Table::REAL_TYPE){
			double diff=atof(v1)-atof(v2);
			if(diff>0)
				return 1;
			else{
				if(diff<0)
					return -1;
				else
					return 0;
			}
		}else
		return(atoi(v1)-atoi(v2));
	}
}


void trimb(Buffer* buffer)
{
	if(buffer!=0){
		char *b=*buffer;
		int n=buffer->getSize()-1;
		int k=0;
		int i=0;
		for(;b[i]>0 && b[i]<=' ';i++);
		if(b[i]=='^' && b[n-1]=='"'){
			for(i++,n--;i<n;++i){
				b[k++]=b[i]^0xff;
			}
			b[k]=0;
			buffer->setSize(k+1);
		}else				
			if(b[i]=='~'){
				for(i++;i<n;++i){
					if(b[i]=='~'){
						break;
					}else{
						b[k++]=b[i]^0xff;
					}
				}
				b[k]=0;
				buffer->setSize(k+1);
			}else
				if(b[i]=='"'){
					for(i++;i<n;++i){
						if(b[i]=='"'){
							break;
						}else{
							b[k++]=b[i];
						}
					}
					b[k]=0;
					buffer->setSize(k+1);
				}else
					if(i>0){
						memcpy(b,b+i,k=n-i);
						b[k]=0;
						buffer->setSize(k+1);
					}					
	}
}


Buffer *Table::getQueryList(Buffer* query,LinkedBuffer* &fs)
{
	char *ANYANDALL="?";
	queryStruct *qx;
	Buffer *qxb=new Buffer(sizeof(queryStruct)*256);
	qx=(queryStruct*)((char*)*qxb);
	memset(*qxb,0,qxb->getSize());
	Buffer *tmpBuf=new Buffer(sizeof(void*)*2*MAXFIELDS);
	char *tmpchar=*tmpBuf;
	int i=0,j=0;
	queryStruct *sortby=&qx[255];
	char order=0;
	int fi=0;
	int rs=0;
	char land=0;
	{
		Buffer **x=(Buffer**)(tmpchar);
		miner *n = new miner();
		if(n->mine(*query,"*WHERE%~%`*`",query->getSize()-1)){
			delete query;
			query=n->getValueFinal(0);
			if(n->mine(*query,"~%*%~%and%~%*",query->getSize()-1))
				land=AND;
			else
				land=0;
			if(land==0){
				while(n->mine(*query,"~%`*`%~%or%~%`*`",query->getSize()-1))  {
					delete query;
					query=n->getValueFinal(1);
					x[i++]=n->getValueFinal(0);
				}
			}
			else{
				while(n->mine(*query,"~%`*`%~%and%~%`*`",query->getSize()-1))  {
					delete query;
					query=n->getValueFinal(1);
					x[i++]=n->getValueFinal(0);
				}
			}
			
		}
		if(query!=0){
			if(((rs=n->mine(*query,"~%`*`%~%ORDER%~%BY%~%`*`",query->getSize()-1))!=0) || ((rs=n->mine(*query,"~%`*`ORDER%~%BY%~%`*`",query->getSize()-1))!=0)|| n->mine(*query,"~%`*`%~%`DESC`~%",query->getSize()-1) || n->mine(*query,"~%`*`%~%`ASC`~%",query->getSize()-1)){
				x[i++]=n->getValueFinal(0);
			}else{
				if(n->mine(*query,"~%`*`",query->getSize()-1)){
					delete query;
					query=0;
					x[i++]=n->getValueFinal(0);
				}
			}
		}
		if(query!=0){
			// looking for sort parameters
			if(rs){ 
				Buffer *fbuff=n->getValueFinal(1);
				char *fname=*fbuff;
				LinkedBuffer *ls=0;
				char corder;
				int orders=0;
				int lsorder=0;
				LinkedBuffer *ps;
				for(int i=0,l=0;;++i){
					if(fname[i]==',' || fname[i]==0){
						char c=fname[i];
						fname[i]=0;
						if(l!=0){
							corder=0;
							lsorder=0;
							Buffer *pb=new Buffer(fname+l+1,i-l+1);
							trim(pb);
							if(n->mine(*pb,"`*`%~%`*`",pb->getSize()-1)){
								orders++;
								lsorder=1;
								if(stricmp(n->getValue(1),"desc")==0)
									corder=1;
								delete pb;
								pb=n->getValueFinal(0);
							}
							if (stricmp(fname,*pb)){
								for(ps=fs;ps!=0;ps=ps->next){
									if(stricmp(*ps,*pb)==0)
										break;
								}
								if(ps==0){
									LinkedBuffer *p=new LinkedBuffer(pb);
									p->setType(corder);
									pb=0;
									if (ls==0)
										fs=p;
									else
										ls->next=p;
									ls=p;
								}
							}
							delete pb;
						}else{
							int p=i-1;
							for(;p>0;--p){
								if(fname[p]==' '||fname[p]=='\t')
									fname[p]=0;
								else
									break;
							}
							int j=-1;
							for(p=0;fname[p]!=0;++p){
								if(fname[p]==' '||fname[p]=='\t'){
									if(j==0)
										j=p;
								}else
									if(j>0){
										orders=1;
										if(stricmp(fname+p,"desc")==0){
											order=1;
										}
										fname[j]=0;
										break;
									}else
										j=0;
							}
						}
						l=i;
						if(c==0)
							break;
					}
				}
				if((orders==1) && lsorder && (corder=='d')){
					order=1;
					for(ps=fs;ps!=0;ps=ps->next)
						ps->setType(1);
				}
				getFieldAny(sortby,fname);
				if(sortby->f!=0){
					if((sortby->rel!=0) && (sortby->f->type==INDEX_TYPE)){
						char *qxbuf=*sortby->rel;
						for(char* qxrel=qxbuf;*qxrel!=0;++qxrel)
							if(*qxrel=='.'){
								qxrel++;
								int z=sortby->rel->getSize();
								Buffer *b=new Buffer(qxbuf,z);
								ps=new LinkedBuffer(b);
								ps->next=fs;
								fs=ps;
								z-=(qxrel-qxbuf);
								memcpy(qxbuf,qxrel,z);
								sortby->rel->setSize(z+1);
								break;
							}
					}else{
						Buffer *b=new Buffer(sortby->f->fieldName,strlen(sortby->f->fieldName)+1);
						ps=new LinkedBuffer(b);
						ps->next=fs;
						fs=ps;
					}
				}
				delete fbuff;
			}else{
				if(stricmp(n->getValue(1),"DESC")==0)
					order=1;
            }
			delete query;
			query=0;
		}
		for(j=0;j<i;++j){
			if(x[j]!=0){
				Buffer *fl;
				if(n->mine(*(x[j]),"~%`*`%~%is%~%`*`",x[j]->getSize()-1)){
					if((fl=n->getValueFinal(0))!=0){
						trim(fl);
						if(getFieldAny(&qx[fi],*fl)!=0){
							char *z=n->getValue(1);
							if(stricmp(z,"unique")==0){
								qx[fi].m=UNIQ;
								qx[fi++].v=0;
							}
						}
						delete fl;
					}
				}else
					if(n->mine(*(x[j]),"~%`*`%~%like%~%`*`",x[j]->getSize()-1)){
						if((fl=n->getValueFinal(0))!=0){
							trim(fl);
							if(getFieldAny(&qx[fi],*fl)!=0){
								Buffer *z=n->getValueFinal(1);
								trimb(z);
								char *b=*z;
								if((strlen(b)>0) && strcmp(b,ANYANDALL)){
									int k;
									for(k=0;b[k]!=0;++k){
										if(b[k]=='*'){
											qx[fi].m=LIKES;
										}
									}
									if(k>0){
										if(qx[fi].m!=LIKES)
											qx[fi].m=LIKE;
										qx[fi++].v=z;
									}
								}else{
									delete z;
								}
							}
							delete fl;
						}
					}else
						if(n->mine(*(x[j]),"`*`<=`*`",x[j]->getSize()-1)){
							if((fl=n->getValueFinal(0))!=0){
								trim(fl);
								if(getFieldAny(&qx[fi],*fl)!=0){
									Buffer* z=n->getValueFinal(1);
									trimb(z);
									char *b=*z;
									if((strlen(b)>0) && strcmp(b,ANYANDALL)){
										qx[fi].m=LTE;
										qx[fi++].v=z;
									}else
										delete z;
								}
								delete fl;
							}
						}else
							if(n->mine(*(x[j]),"`*`>=`*`",x[j]->getSize()-1)){
								if((fl=n->getValueFinal(0))!=0){
									trim(fl);
									if(getFieldAny(&qx[fi],*fl)!=0){
										Buffer* z=n->getValueFinal(1);
										trimb(z);
										char *b=*z;
										if((strlen(b)>0) && strcmp(b,ANYANDALL)){
											qx[fi].m=GTE;
											qx[fi++].v=z;
										}else
											delete z;
									}
									delete fl;
								}
							}else
								if(n->mine(*(x[j]),"`*`<>`*`",x[j]->getSize()-1)){
									if((fl=n->getValueFinal(0))!=0){
										trim(fl);
										if(getFieldAny(&qx[fi],*fl)!=0){
											Buffer* z=n->getValueFinal(1);
											trimb(z);
											char *b=*z;
											if((strlen(b)>0) && strcmp(b,ANYANDALL)){
												qx[fi].m=NTE;
												qx[fi++].v=z;
											}else
												delete z;
										}
										delete fl;
									}
								}else
									if(n->mine(*(x[j]),"`*`>`*`",x[j]->getSize()-1)){
										if((fl=n->getValueFinal(0))!=0){
											trim(fl);
											if(getFieldAny(&qx[fi],*fl)!=0){
												Buffer *z=n->getValueFinal(1);
												trimb(z);
												char *b=*z;
												if((strlen(b)>0) && strcmp(b,ANYANDALL)){
													qx[fi].m=GT;
													qx[fi++].v=z;
												}else
													delete z;
											}
											delete fl;
										}
									}else
										if(n->mine(*(x[j]),"`*`<`*`",x[j]->getSize()-1)){
											if((fl=n->getValueFinal(0))!=0){
												trim(fl);
												if(getFieldAny(&qx[fi],*fl)!=0){
													Buffer* z=n->getValueFinal(1);
													trimb(z);
													char *b=*z;
													if((strlen(b)>0) && strcmp(b,ANYANDALL)){
														qx[fi].m=LT;
														qx[fi++].v=z;
													}else
														delete z;
												}
												delete fl;
											}
										}else
											if(n->mine(*(x[j]),"`*`=`*`",x[j]->getSize()-1)){
												if((fl=n->getValueFinal(0))!=0){
													trim(fl);
													if(getFieldAny(&qx[fi],*fl)!=0){
														Buffer *z=n->getValueFinal(1);
														trimb(z);
														char *b=*z;
														if((strlen(b)>0) && strcmp(b,ANYANDALL)){
															qx[fi].m=EQU;
															qx[fi++].v=z;
														}else
															delete z;
													}
													delete fl;
												}
											}
         }
		 delete x[j];
      }
	  delete n;
	  qx[fi].f=0;
  }
  int qtotal=0;
  queryStruct** qlist=(queryStruct**)(tmpchar);
  int  abort=0;
  for(i=0;i<fi;++i){
	  int found=0;
	  if(qx[i].rel==0){
		  for(j=0;j<qtotal;++j){
			  if(qlist[j]->rel==0){
				  if(qlist[j]->f==qx[i].f){
					  if((qlist[j]->m==NTE) && qx[i].m&RANGE){
						  int dif;
						  if((dif=matchValues(*qx[i].v,*qlist[j]->v,qx[i].f->type))==0){
							  if(land){
								  qlist[j]->m=qx[i].m;
								  qlist[j]->m&=~EQU;
								  found=1;
							  }else{
								  if(qx[i].m&EQU) 
									  abort=2;
								  found=1;
							  }
						  }else{
							  if(land){
								  if(dif>0){
									  if((qx[i].m==GT) || (qx[i].m==GTE)){
										  qlist[j]->m=qx[i].m;
										  delete qlist[j]->v;
										  qlist[j]->v=qx[i].v;
										  qx[i].v=0;
										  found=1;
									  }
								  }else{
									  if(qx[i].m==LT || qx[i].m==LTE){
										  qlist[j]->m=qx[i].m;
										  delete qlist[j]->v;
										  qlist[j]->v=qx[i].v;
										  qx[i].v=0;
										  found=1;
									  }
								  }
							  }else{
								  if(dif>0){
									  if(qx[i].m==LT || qx[i].m==LTE){
										  abort=2;
									  }else
										  found=1;
								  }else{
									  if(qx[i].m==GT || qx[i].m==GTE){
										  abort=2;
									  }else
										  found=1;
								  }
							  }
						  }
					  }else
						  if(qlist[j]->m&RANGE && (qx[i].m==NTE)){
							  int dif;
							  if((dif=matchValues(*qlist[j]->v,*qx[i].v,qx[i].f->type))==0){
								  if(land){
									  qlist[j]->m&=~EQU;
									  found=1;
								  }else{
									  if(qlist[j]->m&EQU) 
										  abort=2;
									  qlist[j]->m=NTE;
									  found=1;
								  }
							  }else{
								  if(land){
									  if(dif>0){
										  if(qlist[j]->m==GT || qlist[j]->m==GTE)
											  found=1;
									  }else{
										  if(qlist[j]->m==LT || qlist[j]->m==LTE)
											  found=1;
									  }
								  }else{
									  if(dif>0){
										  if(qlist[j]->m==LT || qlist[j]->m==LTE){
											  abort=2;
										  }else{
											  delete qlist[j]->v;
											  qlist[j]->v=qx[i].v;
											  qx[i].v=0;
											  qlist[j]->m=NTE;
											  found=1;
										  }
									  }else{
										  if(qlist[j]->m==GT || qlist[j]->m==GTE){
											  abort=2;
										  }else{
											  delete qlist[j]->v;
											  qlist[j]->v=qx[i].v;
											  qx[i].v=0;
											  qlist[j]->m=NTE;
											  found=1;
										  }
									  }
								  }
							  }
						  }else
							  if((qlist[j]->m==EQU) && qx[i].m&RANGE){
								  int dif;
								  if((dif=matchValues(*qx[i].v,*qlist[j]->v,qx[i].f->type))==0){
									  if(land){
										  if(qx[i].m&EQU)
											  found=1;
										  else
											  abort=1;
									  }else{
										  qlist[j]->m=qx[i].m;
										  qlist[j]->m|=EQU;
										  found=1;
									  }
								  }else{
									  if(land){
										  if(dif>0){
											  if(qx[i].m==GT || qx[i].m==GTE)
												  abort=1;
											  else
												  found=1;
										  }else{
											  if(qx[i].m==LT || qx[i].m==LTE)
												  abort=1;
											  else
												  found=1;
										  }
									  }else{
										  if(dif>0){
											  if(qx[i].m==LT || qx[i].m==LTE){
												  qlist[j]->m=qx[i].m;
												  delete qlist[j]->v;
												  qlist[j]->v=qx[i].v;
												  qx[i].v=0;
												  found=1;
											  }
										  }else{
											  if(qx[i].m==GT || qx[i].m==GTE){
												  qlist[j]->m=qx[i].m;
												  delete qlist[j]->v;
												  qlist[j]->v=qx[i].v;
												  qx[i].v=0;
												  found=1;
											  }
										  }
										  
									  }
								  }
							  }else
								  if((qx[i].m==EQU) && qlist[j]->m&RANGE){
									  int dif;
									  if((dif=matchValues(*qx[i].v,*qlist[j]->v,qx[i].f->type))==0){
										  if(land){
											  if(qlist[j]->m&EQU){
												  qlist[j]->m=EQU;
												  found=1;
											  }
											  else
												  abort=1;
										  }else{
											  qlist[j]->m|=EQU;
											  found=1;
										  }
									  }else{
										  if(land){
											  if(dif>0){
												  if(qlist[j]->m==LT || qlist[j]->m==LTE)
													  abort=1;
												  else{
													  found=1;
													  delete qlist[j]->v;
													  qlist[j]->v=qx[i].v;
													  qx[i].v=0;
													  qlist[j]->m=EQU;
												  }
											  }else{
												  if(qlist[j]->m==GT || qlist[j]->m==GTE)
													  abort=1;
												  else{
													  delete qlist[j]->v;
													  qlist[j]->v=qx[i].v;
													  qx[i].v=0;
													  qlist[j]->m=EQU;
													  found=1;
												  }
											  }
										  }else{
											  if(dif>0){
												  if(qlist[j]->m==GT || qlist[j]->m==GTE){
													  found=1;
												  }
											  }else{
												  if(qlist[j]->m==LT || qlist[j]->m==LTE){
													  found=1;
												  }
											  }
										  }
									  }
								  }else
									  if(((qlist[j]->m&~EXCLUDE)==(qx[i].m&~EXCLUDE)) || (((qlist[j]->m&~EQU)==(qx[i].m&~EQU)) && (qx[i].m!=EQU)) ){
										  switch(qx[i].m){
										  case EQU:
										  case NTE:
											  if(qx[i].m==qlist[j]->m){
												  if(matchValues(*qx[i].v,*qlist[j]->v,qx[i].f->type)==0)
													  found=1;
												  else{
													  if((qx[i].m==EQU) && land)
														  abort=1;
													  else
														  if((qx[i].m==NTE) && (land==0))
															  abort=2;
												  }
											  }else{
												  if(matchValues(*qx[i].v,*qlist[j]->v,qx[i].f->type)==0){
													  if(land)
														  abort=1;
													  else
														  abort=2;
												  }else{
													  if(land){
														  if(qx[i].m==EQU){
															  delete qlist[j]->v;
															  qlist[j]->v=qx[i].v;
															  qlist[j]->m=EQU;
															  qx[i].v=0;
														  }
														  found=1;
													  }else{
														  if(qx[i].m==NTE){
															  delete qlist[j]->v;
															  qlist[j]->v=qx[i].v;
															  qlist[j]->m=NTE;
															  qx[i].v=0;
														  }
														  found=1;
													  }
												  }
											  }
											  break;
										  case UNIQ:
											  found=1;
											  break;
										  case GT:
										  case GTE:
											  if(matchValues(*qx[i].v,*qlist[j]->v,qx[i].f->type)>0){
												  if(land){
													  delete qlist[j]->v;
													  qlist[j]->v=qx[i].v;
													  qx[i].v=0;
												  }
											  }else{
												  if(land==0){
													  delete qlist[j]->v;
													  qlist[j]->v=qx[i].v;
													  qx[i].v=0;
												  }
											  }
											  found=1;
											  break;
										  case LT:
										  case LTE:
											  if(matchValues(*qx[i].v,*qlist[j]->v,qx[i].f->type)<0){
												  if(land){
													  delete qlist[j]->v;
													  qlist[j]->v=qx[i].v;
													  qx[i].v=0;
												  }
											  }else{
												  if(land==0){
													  delete qlist[j]->v;
													  qlist[j]->v=qx[i].v;
													  qx[i].v=0;
												  }
											  }
											  found=1;
											  break;
										  }
									  }
									  if(found)
										  break;
				}
			}			
	  }
   }else{
	   char *qxbuf=*(qx[i].rel);
	   for(char* qxrel=qxbuf;*qxrel!=0;++qxrel)
		   if(*qxrel=='.'){
			   qxrel++;
			   int z=qx[i].rel->getSize()-(qxrel-qxbuf);
			   memcpy(qxbuf,qxrel,z);
			   qx[i].rel->setSize(z+1);
			   break;
		   }
   }
   if(abort){
	   for(int l=0;l<fi;++l){
		   delete qx[l].v;
		   delete qx[l].rel;
	   }
	   Buffer *z=0;
	   if(abort==2){
		   z=new Buffer(sizeof(queryStruct)*2);
		   queryStruct *tmp=(queryStruct*)((char*)*z);
		   tmp[0].m=INCLUDE_ALL;
		   tmp[1].m=order;
		   tmp[1].f=sortby->f;
		   tmp[1].rel=sortby->rel;
	   }
	   delete qxb;
	   delete tmpBuf;
	   return z;
   }
   if(found==0)
	   qlist[qtotal++]=&qx[i];
   else{
	   delete qx[i].v;
	   qx[i].v=0;
   }
 }
 int ltotal=qtotal;
 for( i=1;i<qtotal;++i){
	 for(j=0;j<i;++j)
		 if(!(qlist[j]->rel || qlist[i]->rel) && (qlist[i]->f==qlist[j]->f)){
			 if((qx[i].m==UNIQ) && land){
				 if(qlist[j]->m!=LIKE && qlist[j]->m!=LIKES){
					 qlist[j]->m|=UNIQ;
					 qx[i].m=0;
					 ltotal--;
				 }
			 }else{
				 if((qlist[j]->m==UNIQ) && land){
					 if(qx[i].m!=LIKE && qlist[j]->m!=LIKES){
						 qlist[j]->m|=qx[i].m;
						 qlist[j]->v=qx[i].v;
						 qx[i].v=0;
						 qx[i].m=0;
						 ltotal--;
					 }
				 }
			 }
			 if((qlist[j]->m&RANGE) && (qlist[i]->m&RANGE)){
				 ltotal--;
				 if(qlist[j]->m==GTE || qlist[j]->m==GT){
					 qlist[j]->to=qlist[i]->v;
					 qlist[i]->v=0;
				 }else{
					 qlist[j]->to=qlist[j]->v;
					 qlist[j]->v=qlist[i]->v;
					 qlist[i]->v=0;
					 char tmp=(char)qlist[i]->m;
					 qlist[i]->m=qlist[j]->m;
					 qlist[j]->m=tmp;
				 }
				 int m=0;
				 if(qlist[i]->m&EQU)
					 m+=INCLUDE_TO;
				 if(qlist[j]->m&EQU)
					 m+=INCLUDE_FROM;
				 qlist[j]->m=(char)(m+FROMTO);
				 qlist[i]->m=0;
				 if(land){
					 int dif;
					 if((dif=matchValues(*qlist[j]->v,*qlist[j]->to,qlist[j]->f->type))>=0){
						 if(dif == 0 && qlist[j]->m-FROMTO == 3)
							 qlist[j]->m=EQU;
						 else
							 abort=1;
					 }
				 }else{
					 if(matchValues(*qlist[j]->v,*qlist[j]->to,qlist[j]->f->type)>0){
						 Buffer *v=qlist[j]->v;
						 qlist[j]->v=qlist[j]->to;
						 qlist[j]->to=v;
						 int includes=qlist[j]->m&(INCLUDE_TO|INCLUDE_FROM);
						 if((includes!=0) && (includes!=(INCLUDE_TO|INCLUDE_FROM)))
							 qlist[j]->m^=(INCLUDE_TO|INCLUDE_FROM);
						 qlist[j]->m|=EXCLUDE;
					 }
					 else
						 abort=2;
				 }
			 }
		 }
 }
 Buffer *z=0;
 if(abort){
	 for(i=0;i<qtotal;++i){
		 delete qlist[i]->v;
		 delete qlist[i]->to;
		 delete qlist[i]->rel;
     }
	 if(abort==2){
		 z=new Buffer(sizeof(queryStruct)*2);
		 queryStruct *tmp=(queryStruct*)((char*)*z);
		 tmp[0].m=INCLUDE_ALL;
		 tmp[1].m=order;
		 tmp[1].f=sortby->f;
		 tmp[1].rel=sortby->rel;
	 }
	 delete tmpBuf;
	 delete qxb;
	 return z;
 }
 if(ltotal){
	 z=new Buffer(sizeof(queryStruct)*(ltotal+1));
	 queryStruct *tmp=(queryStruct*)((char*)*z);
	 for(i=0,j=0;i<qtotal;++i){
		 if(qlist[i]->m)
			 memcpy(tmp+j++,qlist[i],sizeof(queryStruct));
	 }
	 tmp[j].m=(order|land);
	 tmp[j].f=sortby->f;
	 tmp[j].rel=sortby->rel;
 }else{
	 if(sortby->f){
		 z=new Buffer(sizeof(queryStruct)*(2));
		 queryStruct *tmp=(queryStruct*)((char*)*z);
		 tmp[0].m=INCLUDE_ALL;
		 tmp[1].m=order;
		 tmp[1].f=sortby->f;
		 tmp[1].rel=sortby->rel;
		 tmp[0].rel=0;
	 }
 }
 delete qxb;
 delete tmpBuf;
 return z;
}


void Table::removeFromSelections(int record)
{
    lock();
    char* c=getRecordCached(record);
    if(c!=0){
		for(int i=0;i<MAXSELECTION;++i)  {
			Selection* s;
			if((s=cachedSelection[i])!=0){
				Field *f=s->getField();
				if(matchSelection(c,f,s->getType(),s->getFrom(),s->getTo())){
					recordInfo* node=(recordInfo*)(c+f->offset);
					s->remove(record,node->center);
					if(s->getTotal() < MINCACHESIZE){
						cachedSelection[i]=0;
						delete s;
					}
				}
			}
		}
    }
    release();
}           


extern int repair;

htmlBuffer* Table::makeBuffer(char* b, Field *f,int recId)
{
   char stmp[64];
   switch(f->type){
   case FILE_TYPE:
       {
		   int i;
		   FILEINFO *finfo=(FILEINFO*) b;
		   Buffer *pb=new Buffer((i=strlen(*name))+strlen(f->fieldName)+20);
		   char *p=*pb;
		   strcpy(p,*name);
		   for(;i>0;--i){
			   if(p[i]=='.')
				   break;
		   }
		   if(i==0){
			   delete pb;
			   return 0;
		   }
		   i++;
		   strcpy(p+i,f->fieldName);
		   i=strlen(p);
		   p[i++]=FSLASH;
		   if(finfo->size>0){
			   printFilename(p+i,finfo->recId,finfo->fieldId);
			   File *fil=new File(p);
			   int e=0;
			   if(fil->exists() && (finfo->size==fil->size()) && ((e=(finfo->time==fil->lastWriteTime())) || (finfo->etag==fil->getCrc()))){
				   if((e==0) && (recId!=0)){
					   lock();
					   char* buff = getRecordCached(recId);
					   if(buff){
						   finfo->time=fil->lastWriteTime();
						   if(((VLINK*)(buff+getRecordSize()-sizeof(VLINK)))->sync!=0)
							   dbf->put(buff,recId,getTime());
					   }
					   release();
				   }else
					   fil->setCrc(finfo->etag);
				   char *rname=getFileName(finfo);
				   if (rname!=0)
					   fil->setName(rname);
				   else{
					   Buffer *fnb=new Buffer(fil->filenameOnly()+2+strlen(finfo->extention));
					   char *fn=*fnb;
					   fil->filenameOnly(fn);
					   snprintf(fn+strlen(fn),8,".%s",finfo->extention);
					   fil->setName(fn);
					   delete fnb;
				   }
				   delete pb;
				   return (new htmlBuffer(fil));
			   }else{
				   if((repair==1) && (finfo->size==fil->size())){
					   finfo->etag=fil->getCrc();
					   finfo->time=fil->lastWriteTime();  
					   delete pb;
					   return (new htmlBuffer(fil));
				   }
				   printf("**** file %s inconsistent size=%d/%d\r\n",p,finfo->size,fil->size());
			   }
			   delete fil;
		   }
		   delete pb;
		   return 0;
       }
	   break;
   case CHAR_TYPE:
	   if(b!=0){
		   int i=0;
		   char *s=b;
		   int l=f->size;
		   for(;*s!=0 && i<l;++s,i++);
		   Buffer *buff=new Buffer(b,i+1);
		   s=*buff;
		   s[i]=0;
		   return new htmlBuffer(buff);
	   }
	   break;
   case REAL_TYPE:
      snprintf(stmp,64,"%f",*((double*) b));
      return(new htmlBuffer(stmp));
   case INDEX_TYPE:
   case INT_TYPE:
      snprintf(stmp,64,"%d",*((int*) b));
      return(new htmlBuffer(stmp));
   case BIN_TYPE:
	   return new htmlBuffer(new Buffer(b,fileInfoSize));
   case TIME_TYPE:
      snprintf(stmp,64,"%lu",*((ULONG*)b));
      return(new htmlBuffer(stmp));
   }
return 0;
}


int Table::isChild(char* ptable)
{
   for( SField *sf=fields;sf!=0; sf = (SField *)(((Field *)*sf) ->next)){
		if(((Field *)*sf)->type==INDEX_TYPE)
			if(stricmp(((Field *)*sf)->tableName,ptable)==0){
				return 1;
			}
	}
	return 0;
}



htmlBuffer* Table::getValue(int cid,int recId,char * fieldname)
{
	Field *f = getField(fieldname);
	if(f!=0){
		return getFieldValue(recId,0,f);
	}
	int i=0,j=0;
	for(int k=0;(fieldname[i]!=0) && !((k==0) && (fieldname[i]=='.'));++i){
		if(fieldname[i]=='('){
			if(j==0){
				fieldname[i]=0;
				j=i;
			}
			k++;
		}else
			if(fieldname[i]==')')
				k--;
	}
	if(j!=0){
		f = getField(fieldname);
		fieldname[j]='(';
		if(f!=0)
			return getFieldValue(recId,fieldname);
	}else{
		if(fieldname[i]==0){
			if(stricmp(fieldname,"createdtime")==0){
				char ixBuffer[16];
				snprintf(ixBuffer,16,"%ld",dbf->getCreatedTime(recId));
				return(new htmlBuffer(ixBuffer));
			}else
				if(stricmp(fieldname,"modifiedtime")==0){
					char ixBuffer[16];
					snprintf(ixBuffer,16,"%ld",dbf->getModifiedTime(recId));
					return(new htmlBuffer(ixBuffer));
				}
				
		}
	}
	htmlBuffer* r=0,*l=0;
	if(fieldname[i]=='.'){
		fieldname[i]=0;
		f = getField(fieldname);
		htmlBuffer* x=0;
		if(f && f->type==INDEX_TYPE)
			x=getFieldValue(recId,fieldname);
		else{
			if(f && f->type==FILE_TYPE){
				return getFieldValue(recId,fieldname+i+1,f);
			}
		}
		fieldname[i]='.';
		i++;
		if(x!=0){
			Table *t=dbms->selectTable(cid,f->tableName);
			if(t!=0){
				while(x!=0){
					if(r==0){
						r=t->getValue(cid,atoi(*x),fieldname+i);
						l=r;
					}else{
						l->next=t->getValue(cid,atoi(*x),fieldname+i);
						while(l->next)
							l=l->next;
					}
					htmlBuffer* tmp=x;           
					x=x->next;
					delete tmp;
				}
			}
		}
		return r;
	}
	queryStruct qx;
	memset(&qx,0,sizeof(qx));
	int rc=getFieldAny(&qx,fieldname);
	if(rc && qx.f && qx.f->type==INDEX_TYPE && qx.rel!=0){
		char *s=*qx.rel;
		while(*s){
			if(*s++=='.'){
				break;			
			}
		}
		if(*s!=0){
			htmlBuffer* x=getFieldValue(recId,0,qx.f);
			if(x!=0){
				Table *t=dbms->selectTable(cid,qx.f->tableName);
				if(t!=0){
					while(x!=0){
						if(r==0){
							r=t->getValue(cid,atoi(*x),s);
							l=r;
						}else{
							l->next=t->getValue(cid,atoi(*x),s);
							while(l->next)
								l=l->next;
						}
						htmlBuffer* tmp=x;
						x=x->next;
						delete tmp;
					}
				}
			}
		}
	}
	delete qx.rel;
	return r;
	/*
	Buffer *ntb=new Buffer(sizeof(char*)*8);
	char **ntables=(char**)((char*)*ntb);
	int ntot=0;
	LinkedBuffer* tl=0;
	if(tablelist==0){
		tablelist=new LinkedBuffer(new Buffer(tableName,strlen(tableName)+1));
	}else{
		for(tl=tablelist;tl->next!=0;tl=tl->next){       
			if(stricmp(*tl,tableName)==0){
				ntables[ntot++]=*tl->next;
				if(ntot*((int)sizeof(char*))==ntb->getSize()){
					Buffer *tmp=new Buffer((ntot+8)*sizeof(char*));
					memcpy(*tmp,*ntb,ntb->getSize());
					delete ntb;
					ntb=tmp;
					ntables=(char**)((char*)*ntb);
				}
			}
		}
		tl->next=new LinkedBuffer(new Buffer(tableName,strlen(tableName)+1));
	}
	for( SField *sf=fields;sf!=0; sf = (SField *)(((Field *)*sf) ->next)){
		if(((Field *)*sf)->type==INDEX_TYPE){
			for(i=0;i<ntot;++i){
				if(stricmp(ntables[i],((Field *)*sf)->tableName)==0)
					break;
			}
			if(i==ntot){
				htmlBuffer* x=getFieldValue(recId,0,(Field *)*sf);
				if(x!=0){
					Table *t=dbms->selectTable(cid,((Field *)*sf)->tableName);
					if(t!=0){
						while(x!=0){
							if(r==0){
								r=t->getValue(cid,atoi(*x),fieldname,tablelist);
								l=r;
							}else{
								l->next=t->getValue(cid,atoi(*x),fieldname,tablelist);
								while(l->next)
									l=l->next;
							}
							htmlBuffer* tmp=x;           
							x=x->next;
							delete tmp;
						}
					}
					if(r!=0)
						break;
				}
			}
		}
	}
	delete ntb;
	if(tl==0)
		delete tablelist;
	else{
		delete tl->next;
		tl->next=0;
	}
	return r;
	*/
}




htmlBuffer* Table::getFieldValue(int recId,char * fieldname,Field* f)
{
	Field *of=f;
	if(f==0)
		f = getField(fieldname);
	char ixBuffer[32];
	Buffer *fieldIndex=0;
	int findex=-1;
	if(f==0){
		miner *m=new miner();
		if(m->mine(fieldname,"~%`*`(~%`*`)~%")){
			Buffer *fb=m->getValueFinal(0);
			trim(fb);
			f=getField(*fb);
			delete fb;
		}
		if(f!=0){
			fieldIndex=m->getValueFinal(1);
			if(fieldIndex){
				char *index=*fieldIndex;
				if(*index=='0'){
					index++;
					if(*index>='0' && *index<='9'){
						findex=atoi(index);
						delete fieldIndex;
						fieldIndex=0;
					}
				}
			}
		}
		delete m;
	}
	htmlBuffer* result=0;
	if(f!=0){
		lock();
		char* buff = getRecordCached(recId);
		if(buff!=0){
			int d=getFieldDim(buff,f);
			int n;
			if(f->type==BIN_TYPE){
				n=f->dim;
			}else{
				n=d;
			}
			if(findex==-1){
				if(n>0){
					if(fieldIndex!=0){
						if(f->type!=FILE_TYPE)
							for(int i=0;i<n;++i){
								htmlBuffer *b=makeBuffer(buff+getFieldOffset(f)+i*f->size*elementSize(f->type),f);
								if(b && (stricmp(*fieldIndex,*b)==0)){
									snprintf(ixBuffer,8,"0%d",i+1);
									result = new htmlBuffer(ixBuffer);
									delete b;
									break;
								}
								delete b;
							}
					}else{
						if(of && (f->type==FILE_TYPE) && fieldname){
							FILEINFO *finfo=(FILEINFO*) (buff+getFieldOffset(f));
							if(stricmp(fieldname,"size")==0){
								snprintf(ixBuffer,16,"%lu",finfo->size);
								result = new htmlBuffer(ixBuffer);
							}else
								if(stricmp(fieldname,"time")==0){
									snprintf(ixBuffer,16,"%lu",finfo->time);
									result = new htmlBuffer(ixBuffer);
								}else
									if(stricmp(fieldname,"filename")==0){
										result = new htmlBuffer(finfo->filename);
									}else
										if(stricmp(fieldname,"etag")==0){
											snprintf(ixBuffer,16,"%lu",finfo->etag);
											result = new htmlBuffer(ixBuffer);
										}else
											if(stricmp(fieldname,"extention")==0){
												result = new htmlBuffer(finfo->extention);
											}else
												if(stricmp(fieldname,"fileid")==0){
													printFilename(ixBuffer,finfo->recId,finfo->fieldId);
													result = new htmlBuffer(ixBuffer);
												}
						}else{
							htmlBuffer *t=makeBuffer(buff+getFieldOffset(f),f,recId);
							if(t!=0){
								if(d<=0){
									t->setInvalid();
								}
								if(n==1){
									result = t;
								}
								else{
									htmlBuffer *strt=t;
									int fsize=f->size*elementSize(f->type);
									for(int i=1;i<n;++i){
										t->next=makeBuffer(buff+getFieldOffset(f)+i*fsize,f,recId);
										t=t->next;
										if(t!=0){
											if(d<=i)
												t->setInvalid();
										}else
											break;
									}
									result = strt;
								}
							}
						}
					}
				}
			}else{
				if(findex==0){
					snprintf(ixBuffer,8,"0%d",n);
					result = new htmlBuffer(ixBuffer);
				}else
					if(findex<=n){
						result = makeBuffer(buff+getFieldOffset(f)+(findex-1)*f->size*elementSize(f->type),f);
					}
			}
		}
		delete fieldIndex;
		release();
	}
	return result;
}

void letCacheClear();


void Table::rebuildSearch()
{
	SField *sf;
	Field *f;
	for(sf=fields;sf!=0;sf=(SField*)f->next){
		f=*sf;
		if(((f->flags&BINARY_DATA)==0) && ((f->type==CHAR_TYPE) || (f->type==FILE_TYPE))){
			break;
		}
	}
	if(sf==0)
		return;
	int atotal=dbf->getTotal();
	char tmp[256];
	snprintf(tmp,256,"%s : [%s.%s] Rebuilding (%d recs)",location,dbname,tableName,atotal);
	caravanlog(tmp);
	printf("%s\n",tmp);
	int recId=0;
	for(int i=0;i<atotal;++i){
		recId=(*dbf)[i];
		char* tmpbuff=getRecordCached(recId);
		if(tmpbuff){
			for(sf=fields;sf!=0;sf=(SField*)f->next){
				f=*sf;
				if(getFieldDim(tmpbuff,f)>0){
					if(((f->flags&BINARY_DATA)==0) &&
						((f->type==CHAR_TYPE) || (f->type==FILE_TYPE))){
						htmlBuffer *v=getFieldValue(recId,0,f);
						if(v){
							char fieldId[64];
							snprintf(fieldId,64,"%s.%s.%s",dbname,tableName,f->fieldName);
							WordBasket* wb=new WordBasket(fieldId);
							while(v){
								wb->putWords(v,NEWWORD);
								v=v->next;
							}
							wb->setRecId(recId);
							delete wb;
							deleteHtmlBuffer(v);
						}
					}
				}
			}
			printf("%d\r",i);
			letCacheClear();
		}
	}
	snprintf(tmp,256,"[%s.%s] : Rebuilt ",dbname,tableName);
	caravanlog(tmp);
	printf("%s\n",tmp);
}


void Table::printTree()
{
	int atotal=dbf->getTotal();
	int recId=0;
	SField *sf;
	Field *f;
	int n=0;
	for(int i=1;i<atotal;++i){		
		recId=(*dbf)[i];
		for(sf=fields;sf!=0;sf=(SField*)f->next){
			f=*sf;
			if(checkTree(f,recId))
				n++;
		}
		letCacheClear();
	}
	printf("found %d error in tree\r\n",n);
}


void Table::RepairTable(int files)
{
	SField *sf;
	Field *f;
	char tmp[256];
	if(caches->checkOk()==0){
			snprintf(tmp,256,"%s : [%s.%s] inconsistent cache error detected",location,dbname,tableName);
			caravanlog(tmp);
			printf("%s\n",tmp);

	}
	if(files==0)
		printTree();
	dbf->forceRepair();
	clearCache();
	caches->init();
	int i=0;
	for(i=0;i<MAXSELECTION;++i){
		delete cachedSelection[i];
		cachedSelection[i]=0;
	}
    char *tmpHeader=dbf->getHeader();
	for(sf=fields;sf!=0;sf=(SField*)f->next){
		f=*sf;
		f->root=0;
		f->unodes=0;
		memcpy(tmpHeader+f->hdOffset,f,FIELDSIZE);
	}
	needsRepair=0;
	int atotal=dbf->getTotal();
	snprintf(tmp,256,"%s : [%s.%s] Repairing (%d recs)",location,dbname,tableName,atotal);
	caravanlog(tmp);
	printf("%s\n",tmp);
	int recId=0;
	for(i=0;i<atotal;++i){
		recId=(*dbf)[i];
		char* tmpbuff=getRecordCached(recId);
		if(tmpbuff){
			dbf->bufferedPut(tmpbuff,recId);
			for(sf=fields;sf!=0;sf=(SField*)f->next){
				f=*sf;
				if(getFieldDim(tmpbuff,f)>0){
					if(files){
						if(((f->flags&BINARY_DATA)==0) &&
							((f->type==CHAR_TYPE) || (f->type==FILE_TYPE))){
							htmlBuffer *v=getFieldValue(recId,0,f);
							if(v){
								char fieldId[64];
								snprintf(fieldId,64,"%s.%s.%s",dbname,tableName,f->fieldName);
								WordBasket* wb=new WordBasket(fieldId);
								while(v){
									wb->putWords(v,NEWWORD);
									v=v->next;
								}
								wb->setRecId(recId);
								delete wb;
								deleteHtmlBuffer(v);
							}
						}
					}
					int r=insertNode(recId,f);
					if(r<0){
						snprintf(tmp,256,"Repair: Unrecoverable Error : (EII) inserting field %s in r%d %d\n",f->fieldName,recId,r);
						exitTableError(-1,tmp);
					}else{
						if(f->next==0){
							recordInfo* node=(recordInfo*)(tmpbuff+f->offset);
							if(node->center!=0){
								char *childBuff=getRecordCached(node->center);
								if(childBuff){
									recordInfo* pnode=(recordInfo*)(childBuff+f->offset);
									if(pnode->parent==recId){
										deleteNode(recId,f);
										char tmp[64];
										strcpy(tmp+1,tmpbuff+getFieldOffset(f));
										tmp[0]='Z';
										strcpy(tmpbuff+getFieldOffset(f),tmp);
										insertNode(recId,f);
									}
								}
							}
						}
					}
					memcpy(tmpHeader+f->hdOffset,f,FIELDSIZE);
				}else{
					memset(tmpbuff+f->offset,0,sizeof(recordInfo));
				}
			}
			dbf->flushDat();
			printf("%d\r",i);
			letCacheClear();
		}
	}
	dbf->bufferedPutHeader();
	dbf->flushDats(1);
	snprintf(tmp,256,"[%s.%s] : Repaired",dbname,tableName);
	dbf->RepairWasOK();
	caravanlog(tmp);
	printf("%s\n",tmp);
}


/*-------------------------------------------cache management -----------------------------*/




int cachedSize=0;



typedef struct{
	void *t;
	int r;
}vldata;

void freeCache()
{
	if(vlast!=0){
		vn=0;
		vlast=0;
	}else{
		vn++;
		Vlock->lock();
		if(vn>4 || (cachedSize>cacheMax*1.5)){
			int maxvd=cachedSize/1024;
			Vlock->release();
			Buffer *b=new Buffer(sizeof(vldata)*maxvd);
			vldata *vd=(vldata*)(char*)*b;
			int j=0;
			Vlock->lock();
			int usedcache=cachedSize;
			for(VLINK *v=vhead;(usedcache > cacheMax) && (v!=0);v=v->right){
				vd[j].t=v->table;
				vd[j].r=v->recId;
				v->locked=0;
				usedcache-=v->size;
				if(++j==maxvd){
					maxvd+=4096;
					Buffer *bx=new Buffer(sizeof(vldata)*maxvd);
					vldata *vdx=(vldata*)(char*)*bx;
					memcpy(vdx,vd,j*sizeof(vldata));
					vd=vdx;
					delete b;
					b=bx;
				}
			}
			Vlock->release();
			for(int i=0;i<j;++i){
				((Table*)(vd[i].t))->FreeCachedRecord(vd[i].r);
			}
			delete b;
		}else{
			Vlock->release();
		}
	}
}



Table* findInCache(char *dbname,char* tblname)
{
	Table* f=0;
	Vlock->lock();
	char tmp[256];
	char *tablename=tmp+snprintf(tmp,256,"%s.%s",dbname,tblname)+1;
	Table *vtables[MAXTABLES];
	int vt=0;
	for(VLINK *v=vhead;v!=0;){
		int i=0;
		for(;i<vt;++i){
			if(vtables[i]==v->table)
				break;
		}
		if((i==vt) && (vt<MAXTABLES)){
			vt++;
			vtables[i]=(Table*)(v->table);
			vtables[i]->getTableName(tablename);
			if(stricmp(tablename,tmp)==0){
				f=vtables[i];
				break;
			}
		}
		v=v->right;
	}
	Vlock->release();
	return f;
}

void letCacheClear()
{
	if(cachedSize>(cacheMax*1.5)){
		vlast=0;
		freeCache();
	}
}


class cachelog:public URLhandler{
public:
	cachelog() : URLhandler("cache.txt"){}
	void output(genericObject *fobj,Runnable* r,File *of){
		int usedmem=0;
		Table *vtables[MAXTABLES];
		int vuse[MAXTABLES];
		int vn[MAXTABLES];
		int vt=0;
		int n=0;
		Vlock->lock();
		for(VLINK *v=vhead;v!=0;){
			n++;
			int i=0;
			for(;i<vt;++i){
				if(vtables[i]==v->table)
					break;
			}
			if((i==vt) && (vt<MAXTABLES)){
				vt++;
				vtables[i]=(Table*)v->table;
				vuse[i]=0;
				vn[i]=0;
			}
			vuse[i]+=v->size;
			vn[i]++;
			usedmem+=v->size;
			v=v->right;
		}
		Vlock->release();
		Buffer *mbuff=new Buffer(19000);
		char *b=*mbuff;
		char *tablename=b+18196;
		extern int httpg,httpp,httpc,httpr,httpi,httpj;
		int l=snprintf(b,18196,"Total %d records from %d Tables cached in %d bytes g=%d,p=%d,c=%d,h=%d,i=%d,j=%d\r\n",n,vt,usedmem,httpg,httpp,httpc,httpr,httpi,httpj);
		for(n=0;n<vt;++n){
		        vtables[n]->getTableName(tablename);
			l+=snprintf(b+l,18196-l,"[%s] : %d records using %d bytes\r\n",vtables[n]->getpath(),vn[n],vuse[n]);
		}  
		of->write(b,l);
		delete mbuff;
	};
};


void initcachelog()
{
	new cachelog();
}


void newLink(VLINK* neu)
{
	neu->right=0;
	neu->left=vtail;
	if(vtail)
		vtail->right=neu;
	else
		vhead=neu;
	vlast=vtail=neu;
	neu->locked=1;
	cachedSize+=neu->size;
}


void remLink(VLINK *old)
{
	if(old->right){
		old->right->left=old->left;
	}else{
		vtail=old->left;
	}
	if(old->left){
		old->left->right=old->right;
	}else{
		vhead=old->right;
	}
	cachedSize-=old->size;
}

void Table::DeleteCachedRecord(int recId)
{
	int e;
	lock();
	Vlock->lock();
	if(caches->getPos(recId,&e)){
		CacheData *x=*caches;
		Buffer* buff=x[e].hold;
		VLINK* vl=(VLINK*)((char*)(*buff)+buff->getSize()-sizeof(VLINK));
		remLink(vl);
		delete buff;
		caches->remove(e);
	}
	Vlock->release();
	release();
}


void Table::FreeCachedRecord(int recId)
{
	int e;
	lock();
	Vlock->lock();
	if(caches->getPos(recId,&e)){
		CacheData *x=*caches;
		Buffer* buff=x[e].hold;
		VLINK* vl=(VLINK*)((char*)(*buff)+buff->getSize()-sizeof(VLINK));
		if((vl->locked==0) && (vl->sync)){
			remLink(vl);
			delete buff;
			caches->remove(e);
		}			
	}
	Vlock->release();
	release();
}


/*
void Table::delRecordFromCache(int recId)
{
	lock();
	Vlock->lock();
	DeleteCachedRecord(recId);
	Vlock->release();
	release();
}
*/



void Table::cacheRecord(Buffer* buff,int recId)
{
	int e;
	Vlock->lock();
	VLINK* vl = (VLINK*)((char*)*buff+buff->getSize()-sizeof(VLINK));
	vl->recId=recId;
	vl->size=buff->getSize();
	vl->table=this;
	vl->changed=1;
	CacheData *x=*caches;
	if(caches->getPos(recId,&e)){
		VLINK* v = (VLINK*)((char*)(*(x[e].hold))+x[e].hold->getSize()-sizeof(VLINK));
		remLink(v);
		if(x[e].hold!=buff){
			delete x[e].hold;
			x[e].hold=buff;
		}
	}else{
		CacheData tmp;
		tmp.hold=buff;
		tmp.recId=recId;
		caches->insert(e,tmp);
	}
	newLink(vl);
	Vlock->release();
}

void Table::clearCache()
{
	Vlock->lock();
	CacheData* x = *caches;
	vlast=vtail;
	if (x!=0){
		for(int n=caches->getTotal()-1;n>=0;--n){
			remLink( (VLINK*)((char*)(*(x[n].hold))+x[n].hold->getSize()-sizeof(VLINK)));
			delete x[n].hold;
		}
	}
	Vlock->release();
}



char* Table::mustGetRecordCached(int recId)
{
	char* s=getRecordCached(recId);
	if(s==0){
		char tmp[64];
		snprintf(tmp,64,"%s : Cannot get expected record : %d",location,recId);
		exitTableError(5,tmp);
	}
	return s;
}


int Table::getRecordFromCache(int recId,Buffer *buffer)
{
	if(dbf==0)
		return 0;
	if(recId<=0)
		return 0;
	int e;
	int rc=1;
	int rz=getRecordSize();
	int len=(int)(rz-sizeof(VLINK));
	lock();
	Vlock->lock();
	CacheData *x=*caches;
	int ctotal=caches->getTotal();
	ULONG bz=buffer->getSize();
	if(caches->getPos(recId,&e)){
		char* result=*(x[e].hold);
		VLINK *vl=(VLINK*)(result+len);
		if(vl->recId!=recId){
			char tmp[256];
			snprintf(tmp,256,"%s : [%s.%s] Cache Error %d: wrong Record : %d needs repair!",location,dbname,tableName,caches->checkOk(recId),recId);
			exitTableError(5,tmp);
		}
		memcpy(*buffer,result,bz);
		if(vl!=vtail){
			vl->right->left=vl->left;
			if(vl->left){
				vl->left->right=vl->right;
			}else{
				vhead=vl->right;
			}
			vl->right=0;
			vl->left=vtail;
			vtail->right=vl;
			vlast=vtail=vl;
		}
		vl->locked=1;
	}else{
		if(dbf->checkWriteBuffers(recId)){
			char tmp[256];
			snprintf(tmp,256,"%s : [%s.%s] Cache Error %d: Reading Record : %d needs repair!",location,dbname,tableName,caches->checkOk(recId),recId);
			exitTableError(5,tmp);
		}
		Buffer *buff=new Buffer(rz);
		if(dbf->get(buff,recId)==0){
			delete buff;
			rc=0;
		}else{
			memcpy(*buffer,*buff,bz);
			VLINK* vl = (VLINK*)((char*)*buff+len);
			vl->recId=recId;
			vl->size=rz;
			vl->changed=0;
			vl->table=this;
			CacheData tmp;
			tmp.hold=buff;
			tmp.recId=recId;
			caches->insert(e,tmp);
			newLink(vl);
		}
	}
	Vlock->release();
	release();
	return rc;
}

void Table::setChanged(int recId)
{
	int e;
	Vlock->lock();
	CacheData *x=*caches;
	if(caches->getPos(recId,&e)){
		char* result=*(x[e].hold);
		VLINK* vl = (VLINK*)(result+x[e].hold->getSize()-sizeof(VLINK));
		vl->changed=1;
	}
	Vlock->release();
}

char* Table::getRecordCached(int recId)
{
	if(dbf==0)
		return 0;
	if(recId<=0)
		return 0;
	char* result=0;
	int e;
	int rz=getRecordSize();
	int len=(int)(rz-sizeof(VLINK));
	lock();
	Vlock->lock();
	CacheData *x=*caches;
	if(caches->getPos(recId,&e)){
		result=*(x[e].hold);
		VLINK* vl = (VLINK*)(result+len);
		if(vl->recId!=recId){
			char tmp[256];
			snprintf(tmp,256,"%s : [%s.%s] Cache Error %d: wrong Record : %d needs repair!",location,dbname,tableName,caches->checkOk(recId),recId);
			exitTableError(5,tmp);
		}
		if(vl!=vtail){
			vl->right->left=vl->left;
			if(vl->left){
				vl->left->right=vl->right;
			}else{
				vhead=vl->right;
			}
			vl->right=0;
			vl->left=vtail;
			vtail->right=vl;
			vlast=vtail=vl;
		}
		vl->locked=1;
	}else{
		if(dbf->checkWriteBuffers(recId)){
			char tmp[256];
			snprintf(tmp,256,"%s : [%s.%s] Cache Error %d: Reading Record : %d needs repair!",location,dbname,tableName,caches->checkOk(recId),recId);
			exitTableError(5,tmp);
		}
		Buffer *buff = new Buffer(rz);
		if(dbf->get(buff,recId) == 0){
			delete buff;
		}else{
			VLINK* vl = (VLINK*)((char*)*buff+len);
			vl->recId=recId;
			vl->size=rz;
			vl->changed=0;
			vl->table=this;
			CacheData tmp;
			tmp.hold=buff;
			tmp.recId=recId;
			caches->insert(e,tmp);
			newLink(vl);
			result=*buff;
		}
	}
	Vlock->release();
	release();
	return result;
}



/*
void Table::delRecordFromCache(int recId)
{
	lock();
	int e;
	if(caches->getPos(recId,&e)){
		CacheData *x=*caches;
		Buffer* buff=x[e].hold;
		VLINK* vl = (VLINK*)((char*)(*buff)+buff->getSize()-sizeof(VLINK));
		if(vl->recId==recId){
			remLink(vl);
			delete buff;
			cacheSpace+=getRecordSize();
			caches->remove(e);
		}
	}
	release();
}

void Table::clearCache()
{
	CacheData* x=*caches;
	for(int n=caches->getTotal()-1;n>=0;--n)
		delete x[n].hold;
	head=tail=0;
}

void Table::newLink(VLINK* neu)
{
	neu->left=tail;
	neu->right=0;
	if(tail)
		tail->right=neu;
	else
		head=neu;
	tail=neu;
}


void Table::remLink(VLINK *old)
{
	if(old->right){
		old->right->left=old->left;
	}else{
		tail=old->left;
	}
	if(old->left){
		old->left->right=old->right;
	}else{
		head=old->right;
	}
}



void Table::cacheRecord(Buffer* buff,int recId)
{
	int e;
	int rz=getRecordSize();
	VLINK* vl = (VLINK*)((char*)*buff+rz-sizeof(VLINK));
	vl->recId=recId;
	CacheData *x=*caches;
	if(caches->getPos(recId,&e)){
		VLINK* vl = (VLINK*)((char*)(*(x[e].hold))+rz-sizeof(VLINK));
		remLink(vl);
		if(x[e].hold!=buff){
			memcpy(*(x[e].hold),*buff,x[e].hold->getSize());
			delete buff;
		}
		newLink(vl);
		return;
	}
	CacheData tmp;
	tmp.hold=buff;
	tmp.recId=recId;
	ULONG cacheSize=caches->getTotal();
	caches->insert(e,tmp);
	newLink(vl);
	cacheSpace-=rz;
	while(head && ((cacheSize*rz) > MAXCACHE)){
		if(dbf->getCacheLock(head->recId)==0){
				int p;
				if(caches->getPos(head->recId,&p)){
					x=*caches;
					head=head->right;
					head->left=0;
					delete x[p].hold;
					caches->remove(p);
					cacheSpace+=rz;
					cacheSize--;
				}
		}else{
			break;
		}
	}
}



int Table::freeCache(int size, ULONG *age)
{
   lock();
   int cacheSize=caches->getTotal();
   if(cacheSize > 0){
	   CacheData *x=*caches;
	   int rz=getRecordSize();
	   int freed=0;
	   int k=0;
	   for(VLINK *v=head;v!=0;v=v->right)
		   if(dbf->getCacheLock(v->recId)==0){
			   int p;
			   if(caches->getPos(v->recId,&p)){
				   remLink(v);
				   delete x[p].hold;
				   x[p].recId=0;
				   size-=rz;
				   freed+=rz;
				   k++;
			   }else
				   break;
		   }
		   if(k){
			   caches->removeAll(0,k);
			   cacheSpace+=freed;
		   }
   }
   release();
   return size;
}


char* Table::mustGetRecordCached(int recId)
{
	char* s=getRecordCached(recId);
	if(s==0)
		exitTableError(5,"Cannot get expected Record");
	return s;
}


int Table::getRecordFromCache(int recId,Buffer *buffer)
{
	if(dbf==0)
		return 0;
	if(recId<=0)
		return 0;
	int e;
	CacheData *x=*caches;
	ULONG rz=buffer->getSize();
	if(caches->getPos(recId,&e)){
		char* result=*(x[e].hold);
		if(((VLINK*)(result+rz-sizeof(VLINK)))->recId==recId){
			memcpy(*buffer,result,rz);
			return 1;
		}
	}
	if(dbf->get(buffer,recId)){
		if((rz*caches->getTotal()) < (MAXCACHE*4/5)){
			Buffer *buf=new Buffer(*buffer,buffer->getSize());
			cacheRecord(buf,recId);
		}
		return 1;
	}
	return 0;
}

char* Table::getRecordCached(int recId)
{
	if(dbf==0)
		return 0;
	if(recId<=0)
		return 0;
	char* result;
	int rz=getRecordSize();
	int e;
	lock();
	CacheData *x=*caches;
	if(caches->getPos(recId,&e)){
		result=*(x[e].hold);
		VLINK* vl = (VLINK*)(result+rz-sizeof(VLINK));
		if(vl->recId==recId){
			if(vl!=tail){
				remLink(vl);
				newLink(vl);
			}
			release();
			return result;
		}
		release();
		return 0;
	}
	Buffer *buff = new Buffer(rz);
	if(dbf->get(buff,recId) == 0){
		delete buff;
		release();
		return 0;
    }
	cacheRecord(buff,recId);
	release();
	result=*buff;
	if(((VLINK*)(result+rz-sizeof(VLINK)))->recId==recId)
		return result;
	return 0;
}

*/
/*-----------------------------------end cache functions--------------------------------------*/






int Table::exists(int rec)
{
   lock();
   char *r=getRecordCached(rec);
   release();
   return r!=0;
}




void addNewChild(char* db,char*tbl,char* newc);

int Table::createTableFile()
{
	int n=0;
	if(stricmp(dbname,"caravan")==0){
		if(stricmp(tableName,"queue")==0 || stricmp(tableName,"msgInfo")==0)
			n=1;
	}
	if(n==0){
		addField(sORIGIN,CHAR_TYPE,32,1,SYSTEM|BINARY_DATA,location);
    }
	recordSize=0;
	if((n = getHeaderSize())!=0){
		Buffer *fb = new Buffer(n);
		char* b = *fb;
		char* hb=b;
		*((int*) b) = nFields;
		b+=sizeof(int);
		*((int*) b) = maxRecords;
		b+=sizeof(int);
		SField *sf=fields;
		Field *f;
		recordSize=0;
		nFields=0;
		while(sf){
			f = *sf;
			if(f->size > 0) {
				memcpy(b,f,FIELDSIZE);
				f->hdOffset=b-hb;
				b+=FIELDSIZE;
				recordSize+=getFieldSize(f);
				nFields++;
			}else{
				delete fb;
				return(0);
			}
			sf=(SField*)f->next;
		}
		if(dbf==0){
			dbf = new TableFile(*name,dbl,recordSize,headerSize=b-hb);
		}else{
			dbf->setLockable(dbl);
			if(dbf->getRecordSize()!=recordSize){
				delete fb;
				return 0;
			}
		}
		dbf->putHeader(hb);
		delete fb;
		sf=fields;
		SField *tmp;
		fields = 0;
		int offset=0;
		Buffer *dv = new Buffer(recordSize);
		b=*dv;
		while(sf){
			f=*sf;
			tmp=(SField*)f->next;
			f->next = fields;
			f->offset = offset+sizeof(char);
			offset += getFieldSize(f);
			fields = sf;
			sf = tmp;
		}
		sf = fields;
		while(sf){
			f = *sf;
			sf=(SField*)f->next;
			if(f->type==INDEX_TYPE)
				addNewChild(dbname,f->tableName,tableName);
			memcpy(b+getFieldOffset(f),f->defaultValue,f->size*elementSize(f->type));
			f->defaultValue = b+getFieldOffset(f);
		}
		delete defaultCache;
		defaultCache=dv;
		if(dbf->getTotal()>0)
			dbf->put(b,0);
		else
			dbf->add(b);
		dbf->flush();
		getTableInfo(1);
		return(1);
    }
	return(0);
}

void Table::cleanupFieldList()
{
	SField *sf;
	while(fields){
		sf = fields;
		fields = (SField *)(((Field *)*sf) ->next);                            
		delete sf;
	}
}

int Table::addField(char* fieldName,int fieldType,int fieldSize,int dimension,int flags,char* defaultValue,int ok)
{
	while ((*fieldName!=0) && (*fieldName<=' ')){
		fieldName++;
	}
	int i=strlen(fieldName)-1;
	for(;i>0;--i){
		if(fieldName[i]<=' ')
			fieldName[i]=0;
		else
			break;
	}
	if(i==0){
		return 1;
	}
	if(getField(fieldName)){
		return 1;
	}
	SField* sf=new SField();
	Field* f=*sf;
	memset(f,0,sizeof(Field));
	f->type = fieldType;
	if(fieldType==INDEX_TYPE){
		miner *m=new miner();
		if(m->mine(fieldName,"`*`(`*`)")){
			strcpy(f->fieldName,m->getValue(0));
			strcpy(f->tableName,m->getValue(1));
		}
		delete m;
	}else
		strcpy(f->fieldName,fieldName);
	if(f->type != 0){
		if(fieldSize)
			f->size = fieldSize;
		else
			f->size=1;
		if(dimension)
			f->dim = dimension;
		else
			f->dim=1;
		if(defaultCache == 0){
			defaultCache = new Buffer(32000);
			recordSize=0;
		}
		f->defaultValue = (((char*)*defaultCache)+recordSize);
		memset(f->defaultValue++,0,getFieldSize(f));
		if(defaultValue){
			if(ok)
				memcpy(f->defaultValue,defaultValue,f->size*elementSize(f->type));
			else
				evaluate(f->defaultValue,defaultValue,f);
		}
		f->flags=flags;
		f->next = fields;
		fields = sf;
		recordSize+=getFieldSize(f);
		return(0);
	}else{
		delete sf;
		return 1;
	}
}



int Table::getRecordSize()
{
	if(recordSize>0 && headerSize>0)
		return(recordSize+sizeof(VLINK));
	SField *sf=fields;
	Field *f;
	int fs;
	nFields=0;
	recordSize=0;
	headerSize=0;
	while(sf){
		f = *sf;
		fs=0;
		headerSize+=FIELDSIZE;
		if(f->size > 0) {
			fs=getFieldSize(f);
		}else{
			recordSize = headerSize = 0;
			return(0);
		}
		recordSize+=fs;
		nFields++;
		sf=((SField*)f->next);
	}
	headerSize+=sizeof(int)*2;
	return(recordSize+sizeof(VLINK));
}




int Table::elementSize(int type)
{

         switch(type){
         case CHAR_TYPE:
            return sizeof(char);
		 case INDEX_TYPE:
         case INT_TYPE:
            return(sizeof(int));
         case TIME_TYPE:
            return(sizeof(int));
		 case REAL_TYPE:
			 return 16;
         case FILE_TYPE:
		 case BIN_TYPE:
            return(fileInfoSize);
         }
 return(0);
}

int Table::charWidth(Field *f)
{

         switch(f->type){
         case CHAR_TYPE:
            return ((f->size+1)*f->dim);
 		 case INDEX_TYPE:
		 case INT_TYPE:
            return(12*f->dim);
		 case REAL_TYPE:
         case TIME_TYPE:
            return(32*f->dim);
         case FILE_TYPE:
            return(fileInfoSize);
         }
 return(0);
}



int Table::exists()
{
	if(dbf == 0){
		char* s=(char*)alloca(name->getSize());
		strcpy(s,*name);
		int pl=strlen(s);
		for(;pl>0 ;pl-- ) {
			if(s[pl]== FSLASH || s[pl]==SLASH)
				break;
		}
		if(pl>0){
			s[pl]=0;
			finder *f = new finder(s);
			int n = f->findFile(s+pl+1);
			delete f;
			return(n);  
		}
	}
	return(1);
}


#include "properties.h"


void Table::evaluate(char* dest,char* string,Field* f)
{                      
	switch(f->type){
	case CHAR_TYPE:
	case FILE_TYPE:
		strncpy(dest,string,f->size);
		dest[f->size-1]=0;
		break;
	case REAL_TYPE:
		*(double*) dest=atof(string);
		break;
	case INT_TYPE:
		*(int *) dest = atoi(string);
		break;
	case INDEX_TYPE:
		if(*string > '9' || *string < '0'){
			*(ULONG*)dest=getKeyNo(dbname,f->tableName,string);
			break;
		}
	case TIME_TYPE:
		*(ULONG*)dest=(ULONG)atoi(string);
		break;
	}
}

int Table::evaluate(char* dest,htmlBuffer* string,Field* f,int recId,int fieldId)
{
	if(string!=0){
		switch(f->type){
		case CHAR_TYPE:
			{
				int n=string->getSize();
				if(n>f->size)
					n=f->size;
				File* fd=string->getFile();
				if(fd==0){
					memcpy(dest,(char*)*string,n);
				}else{
					if(n>1){
						fd->seekTo(0);
						n=fd->read(dest,n);
						if(n<f->size)
							n++;
						fd->close();
					}
				}
				dest[n-1]=0;
				if((f->flags&BINARY_DATA)==0){
					char *b=dest;
					while(*b>0 && *b==' ')
						b++;
					if(*b){
						n=strlen(b)-1;
						for(;(n>0) && (b[n]==' ');--n);
						if(b>dest)
							memcpy(dest,b,n+1);
						dest[n+1]=0;
					}else
						*dest=0;
				}
			}
			break;
		case REAL_TYPE:
			*(double*) dest=atof(*string);
			break;
		case INT_TYPE:
			{
				*(int *) dest = atoi(*string);
				break;
			}
		case INDEX_TYPE:
			if(*((char*)*string) > '9' || *((char*)*string) < '0'){
				*(ULONG*)dest=getKeyNo(dbname,f->tableName,*string);
				break;
			}
		case TIME_TYPE:
			{
				*(ULONG*)dest = (ULONG)atoi(*string);
				break;
			}
		case BIN_TYPE:
			memcpy(dest,(char*)*string,fileInfoSize);
			break;
		case FILE_TYPE:
			FILEINFO *finfo=(FILEINFO*)dest;
			memset(dest,0,fileInfoSize);
			if(recId==0){
				lock();
				recId=finfo->recId=dbf->incUrecId();
				release();
			}else{
				finfo->recId=recId;
			}
			if(string->getFile()){
				int i;
				File *inputFile=string->getFile();
				putFileName(finfo,inputFile);
				char *string=inputFile->getName();
				Buffer *pb=new Buffer((i=strlen(*name))+strlen(f->fieldName)+32);
				char *p=*pb;
				strcpy(p,*name);
				for(;i>0;--i){
					if(p[i]=='.')
						break;
				}
				if(i==0){
					break;
				}
				i++;
				strcpy(p+i,f->fieldName);
				mkDirectory(p);
				i=strlen(p);
				p[i++]=FSLASH;
				RealFile *lockf=0;
				int nread;
				if(inputFile->exists()==0){
					break;
				}
				printFilename(p+i,recId,fieldId);
				if(stricmp(p,string)==0){
					break;
				}
				ULONG z=inputFile->lastWriteTime();
				lock();
				lockf=new RealFile(p);
				if(lockf->create()==0){
					fieldId+=1000;
					while(fieldId<2000){
						delete lockf;
						printFilename(p+i,recId,fieldId);
						lockf=new RealFile(p);
						if(lockf->create()){
							break;
						}
						fieldId+=1;
					}
				}
				finfo->fieldId=fieldId;
				Buffer *tmpBuff=new Buffer(BFSIZE);
				char *rwbuff=*tmpBuff;
				int kf=strlen(tmpDirectory);
				int purge=((kf>0) && (strnicmp(tmpDirectory,string,kf-1)==0));
				ULONG fcs=inputFile->getCrc();
				kf=(fcs==INITFCS32);
				if(purge){
					lockf->close();
					lockf->deleteFile();
					if(inputFile->rename(p)){
						release();
						delete lockf;
						if (kf){
							inputFile->seekTo(0);
							do{
								nread=inputFile->read(rwbuff,BFSIZE);
								for(int i=0;i<nread;++i)
									fcs = (((fcs) >> 8) ^ fcstab32[((fcs) ^ (UCHAR)(rwbuff[i])) & 0xff]);
							}while(nread==BFSIZE);
						}
						finfo->size=inputFile->size();
						finfo->time=z;
					}else{
						goto copyFileToTable;
					}
				}else{
copyFileToTable:
				release();
				RealFile *out = lockf;
				inputFile->seekTo(0);
				char *b=inputFile->getBuffer();
				if(b!=0){
					nread=inputFile->size();
					if(kf){
						for(int i=0;i<nread;++i)
							fcs = (((fcs) >> 8) ^ fcstab32[((fcs) ^ (UCHAR)(b[i])) & 0xff]);
					}
					out->write(b,nread);
				}else{
					do{
						nread=inputFile->read(rwbuff,BFSIZE);
						if(kf){
							for(int i=0;i<nread;++i)
								fcs = (((fcs) >> 8) ^ fcstab32[((fcs) ^ (UCHAR)(rwbuff[i])) & 0xff]);
						}
						out->write(rwbuff,nread);
					}while(nread==BFSIZE);
				}
				out->setLastWriteTime(z);
				finfo->size=out->size();
				finfo->time=out->lastWriteTime();
				delete out;
				}
				finfo->etag=fcs;
				inputFile->close();
				delete tmpBuff;
				delete pb;
			}else{
				if(string->isBuff()==0)
					break;
				if(string->getSize()<=0)
					break;
				int i;
				Buffer *pb=new Buffer((i=strlen(*name))+strlen(f->fieldName)+32);
				char *p=*pb;
				strcpy(p,*name);
				for(;i>0;--i){
					if(p[i]=='.')
						break;
				}
				if(i==0){
					break;
				}
				i++;
				strcpy(p+i,f->fieldName);
				mkDirectory(p);
				i=strlen(p);
				p[i++]=FSLASH;
				printFilename(p+i,recId,fieldId);
				strcpy(finfo->filename,p+i);
				lock();
				RealFile *lockf=new RealFile(p);
				if(lockf->create()==0){
					fieldId+=1000;
					while(fieldId<2000){
						delete lockf;
						printFilename(p+i,recId,fieldId);
						lockf=new RealFile(p);
						if(lockf->create()){
							finfo->fieldId=fieldId;
							break;
						}
						fieldId+=1;
					}
				}
				if(f->flags&BINARY_DATA){
					strcpy(finfo->extention,"IMG");
				}else{
					strcpy(finfo->extention,"TXT");
				}
				RealFile *x=lockf;
				release();
				finfo->size=x->write(*string,string->getSize()-1);
				x->seekTo(0);
				finfo->time=getTime();
				ULONG fcs=INITFCS32;
				Buffer *tmpBuff=new Buffer(BFSIZE);
				char *rwbuff=*tmpBuff;
				int nread; 
				do{
					if((nread=x->read(rwbuff,BFSIZE))>0)
						for(int i=0;i<nread;++i)
							fcs = (((fcs) >> 8) ^ fcstab32[((fcs) ^ (UCHAR)(rwbuff[i])) & 0xff]);
				}while(nread==BFSIZE);
				delete tmpBuff;
				finfo->etag=fcs;
				delete pb;
				delete x;
			}
			break;
		}
   }
   return recId;
}



char* Table::translateType(Field *f)
{                      
	switch(f->type){
	case REAL_TYPE:
		return ("RealNumber");
	case INDEX_TYPE:
		return("RELATION");
	case CHAR_TYPE:
		return("String");
	case INT_TYPE:
		return("Numeric");
	case TIME_TYPE:
		return("Time");
	case FILE_TYPE:
		if(f->flags&BINARY_DATA)
			return("IMAGE");
		else
			return("TEXT");
		
	}
	return("Unknown");
}

char* Table::flagList(int flags)
{
   static char flagl[8];
   char* s=flagl;
   if(flags&MANDATORY)
      *s++='M';
   if(flags&UNIQUE)
      *s++='U';
   if(flags&SYSTEM)
      *s++='S';
   if(flags&LOCAL)
      *s++='L';
   if(flags&BINARY_DATA)
      *s++='B';
   *s=0;
   return(flagl);
}




void Table::sendTable(char *loc)
{
	/*
	if(loc && *loc){
     int tot=dbf->getTotal();
     for(int i=1;i<tot;++i){
       if(putInQueue(this,(*dbf)[i],new htmlBuffer(loc),0,-1)==0)
          break;
     }
	}
	*/
}


struct tableDef{
      char fieldName[64];
      int type;
      int size;
      int dim;
      int flags;
      int defaultValue;
      int dvSize;
      };

File* Table::getTableInfo(int remake)
{
	char wsc[512];
	RealFile *ti;
	snprintf(wsc,256,"%s%c%s.db%c%s.xml",dbHome,FSLASH,dbname,FSLASH,tableName);
	ti=new RealFile(wsc);
	if(ti->exists()){
		if(remake)
			ti->replace();
		else{
			goto tableInfoDone;
		}
	}else
		ti->create();
	if(dbf->nomodify()){
		snprintf(wsc,512," <Table db=\"%s\" table=\"%s\" maxrecords=\"%d\" modify=\"no\">\r\n",dbname,tableName,maxRecords); 
	}else{
		snprintf(wsc,512," <Table db=\"%s\" table=\"%s\" maxrecords=\"%d\">\r\n",dbname,tableName,maxRecords); 
	}
	ti->write(wsc);
	SField *sf;
	Field *f;
	for(sf=fields;sf!=0;sf = (SField *)(((Field *)*sf) ->next)){
		f = *sf;
		if((f->flags&SYSTEM) == 0){
			char ftyp[32];
			if(f->type!=INDEX_TYPE)
				strcpy(ftyp,translateType(f));
			else
				snprintf(ftyp,64,":%s",f->tableName);
			snprintf(wsc,512,"  <Field name=\"%s\" type=\"%s\" size=\"%d\" dim=\"%d\"",f->fieldName,ftyp,f->size,f->dim);
			ti->write(wsc);
			if(f->flags&MANDATORY)
				ti->write(" mandatory=\"true\"");
			if(f->flags&UNIQUE)
				ti->write(" unique=\"true\"");
			if(f->flags&LOCAL)
				ti->write(" local=\"true\"");
			if(f->flags&BINARY_DATA)
				ti->write(" binary=\"true\"");
			if(f->flags&HIDDEN)
				ti->write(" hidden=\"true\"");
			if(((f->defaultValue==0) || (stricmp(ftyp,"unknown")==0)) || ((f->type==FILE_TYPE || f->type==CHAR_TYPE) && *f->defaultValue==0))
				ti->write(" />\r\n");
			else{
				ti->write(">\r\n   <default>\r\n    ");
				if(f->type==CHAR_TYPE)
					ti->write(f->defaultValue);
				else{
					htmlBuffer *df=makeBuffer(f->defaultValue,f);
					if(df){
						ti->write(*df);
						delete df;
					}
				}
				ti->write("\r\n   </default>\r\n  </Field>\r\n");
			}
			
		}
	}
	ti->write(" </Table>\r\n");
	if(remake){
		delete ti;
		return 0;
	}
tableInfoDone:
	ti->close();
	ti->setReadonly(1);
	return ti;
}

Buffer* Table::exportTableDef()
{
    SField *sf;
    Field *f;
    int i=0;
    int ds=0;
    for(sf=fields;sf!=0;sf = (SField *)(((Field *)*sf) ->next)){
     f = *sf;
     i++;
     if(f->defaultValue && (f->defaultValue!=nullString))
      ds+=f->size*elementSize(f->type);
     }
    Buffer *tabledef=new Buffer(i*sizeof(tableDef)+ds+sizeof(int)*2);
    char *b=*tabledef;
    char *b0=b;
    *((int*)b)=i;
    b+=sizeof(int);
    *((int*)b)=maxRecords;
    b+=sizeof(int);
    char *dv=b+sizeof(tableDef)*i;
    memset(b,0,dv-b);
    for(sf=fields;sf!=0;sf = (SField *)(((Field *)*sf) ->next)){
     tableDef* df=(tableDef*)b;
     b+=sizeof(tableDef);
     f = *sf;
     strcpy(df->fieldName,f->fieldName);
     df->type=f->type;
     df->flags=f->flags;
     df->dim=f->dim;
     df->size=f->size;
     if(f->defaultValue && (f->defaultValue!=nullString)){
      df->defaultValue=dv-b0;
      memcpy(dv,f->defaultValue,f->size*elementSize(f->type));
      df->dvSize=f->size*elementSize(f->type);
      dv+=df->dvSize;
      }
    }
   return tabledef;
}


genericObject* Table::exportData(int recno, htmlBuffer *fieldList,int TableDef)
{
	htmlObject *z = new htmlObject();
	z->putValue(sDB,dbname);
	z->putValue(sTABLE,tableName);
	z->putValue(sFROM,location);
	Field *f;
	if(TableDef!=0)
		z->putValue(new Buffer(sTABLEDEF,lTABLEDEF),new htmlBuffer(exportTableDef()));
	int system=0;
	if(fieldList)
		system=((stricmp(*fieldList,dbname)==0) && (fieldList->next!=0) && (stricmp(*fieldList->next,tableName)==0));
	if(system && fieldList->next->next){
		int n=atoi(*fieldList->next->next);
		if(n!=0){
			recno=n;
			fieldList=fieldList->next->next->next;
		}
	}
	int originID=0;
	if(fieldList==0){
		for(SField *sf=fields;sf!=0;sf=(SField*)f->next){
			f=*sf;
			if((f->flags&LOCAL)==0){
				    if(stricmp(sORIGIN,f->fieldName)==0)
						originID=1;
					htmlBuffer *x=getFieldValue(recno,0,f);
					if (f->type==INDEX_TYPE){
						htmlBuffer *y=0;
						htmlBuffer *yl=0;
						while(x){
							int recn=atoi(*x);
							htmlBuffer *t=x->next;
							delete x;
							x=t;
							if((t=getKey(dbname,f->tableName,recn))!=0){
								if(y)
									yl->next=t;
								else
									y=t;
								yl=t;
							}
						}
						x=y;
					}
					z->putValue(new Buffer(f->fieldName,strlen(f->fieldName)+1),x);
			}
		}
	}else{
		if(atoi(*fieldList)==recno){
			z->putValue("delete_","true");
		}else
		for(htmlBuffer *fl=fieldList;fl!=0;fl=fl->next){
			if((f=getField(*fl))!=0){
				if((f->flags&LOCAL)==0){
					htmlBuffer *x=getFieldValue(recno,0,f);
					if (f->type==INDEX_TYPE){
						htmlBuffer *y=0;
						htmlBuffer *yl=0;
						while(x){
							int recn=atoi(*x);
							htmlBuffer *t=x->next;
							delete x;
							x=t;
							if((t=getKey(dbname,f->tableName,recn))!=0){
								if(y)
									yl->next=t;
								else
									y=t;
								yl=t;
							}
						}
						x=y;
					}
					htmlBuffer *xb=x;
					if(xb==0){
						xb=new htmlBuffer("");
					}
					z->putValue(new Buffer(f->fieldName,strlen(f->fieldName)+1),xb);
				}
			}
		}
	}
	if(originID==0){
		htmlBuffer *x=getFieldValue(recno,sORIGIN);
		if(x==0){
			char tmp[32];
			snprintf(tmp,32,"%s%u",location,recno);
			x=new htmlBuffer(tmp);
		}
		if(x!=0)
			z->putValue(new Buffer(sORIGIN,lORIGIN),x);
	}
	return z;
}


int Table::importData(genericObject *form)
{
 int recNo=0;
 char* loc=form->showValue(sORIGIN);
 if(loc!=0)
	 recNo=getKeyNo(dbname,tableName,loc);
 if(recNo>0){
   loc=form->showValue("delete_");
   if(loc && strcmp(loc,"true")==0)
	   deleteRecord(recNo,form->getValue(sFROM),1);
   else
	   recNo=updateRecord(form,recNo,2);
 }
 else
   recNo=insertRow(form,2);
 return recNo;
}


int Table::makeTable(xmlObject* x)
{
	htmlBuffer *val=x->getValue("Field(00)");
	if(val){
		int nf=atoi(*val);
		delete val;
		int changed=0;
		if(nf>0){
			lock();
			editLock->lock();
			Buffer *defaultCachebak=defaultCache;
			int recordSizebak=recordSize;
			Buffer* newdefaultCache = new Buffer(32000);
			SField* fieldsbak=fields;
			SField* sf;
			SField* newfields=0;
			int newrecordSize=0;
			x->putValue(new Buffer("_node",6),new htmlBuffer("Field"));
			for(int i=0;i<nf;++i){
				val=x->getValue("_attribute(name)");
				if(val){
					char fieldName[40];
					strcpy(fieldName,*val);
					delete val;
					if(fieldName[0]!='_'){
						Field *cf=getField(fieldName);
						int nsize=1;
						int ndim=1;
						int nflags=NORMAL;
						int ntype=0;
						if(cf){
							nsize=cf->size;
							ndim=cf->dim;
							ntype=cf->type;
							nflags=cf->flags;
						}
						val=x->getValue("_attribute(newname)");
						if(val!=0){
							if(cf!=0){
								Buffer *b=val->getBuff();
								trim(b);
								if(b->getSize()>1){
									for(sf=newfields;sf!=0;sf=(SField *)(((Field *)*sf)->next)){
										if(stricmp(((Field*)*sf)->fieldName,*b)==0){
											break;
										}
									}
									if(sf==0){
										SField *z= new SField();
										Field *f=*z;
										memcpy(f,cf,sizeof(Field));
										strncpy(f->fieldName,*b,15);
										f->fieldName[15]=0;
										strcpy(fieldName,f->fieldName);
										modifyField(f,cf);
										delete z;
										cf=getField(fieldName);
										if(cf==0)
											return 0;
										fieldsbak=fields;
									}
								}
								delete b;
							}else{
								fields=newfields;
								cleanupFieldList();
								fields=fieldsbak;
								delete newdefaultCache;
								release();
								return 0;
							}
							delete val;
						}
						val=x->getValue("_attribute(size)");
						if(val){
							nsize=atoi(*val);
							delete val;
						}
						val=x->getValue("_attribute(dim)");
						if(val){
							ndim=atoi(*val);
							delete val;
						}
						val=x->getValue("_attribute(type)");
						if(val){
							if(stricmp(*val,"String")==0)
								ntype=CHAR_TYPE;
							else{
								nsize=1;
								if(stricmp(*val,"TEXT")==0)
									ntype=FILE_TYPE;
								else
									if(stricmp(*val,"IMAGE")==0){
										ntype=FILE_TYPE;
										nflags=BINARY_DATA;
									}else
										if(stricmp(*val,"TIME")==0)
											ntype=TIME_TYPE;
										else
											if(stricmp(*val,"Numeric")==0)
												ntype=INT_TYPE;
											else
												if(stricmp(*val,"RealNumber")==0)
													ntype=REAL_TYPE;
												else{
													char* tmp=*val;
													if(*tmp==':'){
														ntype=INDEX_TYPE;
														int n=strlen(fieldName);
														fieldName[n++]='(';
														strncpy(fieldName+n,tmp+1,15);
														fieldName[n+15]=0;
														n=strlen(fieldName);
														fieldName[n++]=')';
														fieldName[n++]=0;
													}
												}
							}
							delete val;
							int xflags=0;
							if((val=x->getValue("_attribute(mandatory)"))!=0){
								if(stricmp(*val,"yes")==0 || stricmp(*val,"true")==0)
									xflags|=MANDATORY;
								delete val;
							}
							if((val=x->getValue("_attribute(unique)"))!=0){
								if(stricmp(*val,"yes")==0 || stricmp(*val,"true")==0)
									xflags|=UNIQUE;
								delete val;
							}
							if((val=x->getValue("_attribute(local)"))!=0){
								if(stricmp(*val,"yes")==0 || stricmp(*val,"true")==0)
									xflags|=LOCAL;
								delete val;
							}
							if((val=x->getValue("_attribute(binary)"))!=0){
								if(stricmp(*val,"yes")==0 || stricmp(*val,"true")==0)
									xflags|=BINARY_DATA;
								delete val;
							}
							if((val=x->getValue("_attribute(hidden)"))!=0){
								if(stricmp(*val,"yes")==0 || stricmp(*val,"true")==0)
									xflags|=HIDDEN;
								delete val;
							}
							if(xflags!=0)
								nflags=xflags;
							val=x->getValue("default");
							if (nsize && ndim && ntype){
								char *s=0;
								if(val){
									Buffer *b=val->getBuff();
									if(b!=0){
										trim(b);
										s=*b;
									}
								}
								fields=newfields;
								recordSize=newrecordSize;
								defaultCache=newdefaultCache;
								if(addField(fieldName,ntype,nsize,ndim,nflags,s)==0){
									if(cf){
										Field *cfx=*fields;
										if((cfx->type==cf->type) && (cfx->size==cf->size) && (cfx->dim==cf->dim) && (cf->flags==cfx->flags)){
											if(cf->defaultValue && cfx->defaultValue){
												if(compare(cf->defaultValue,cfx->defaultValue,cf->type)!=0){
													changed++;
												}
											}else{
												if(cf->defaultValue || cfx->defaultValue){
													changed++;
												}
											}
										}else{
											if(cfx->type==FILE_TYPE && cf->type==CHAR_TYPE){
												cfx->type=NEWFILE_TYPE;
											}
											changed++; // field changed
										}
									}else{
										changed++;// new field
									}
								}
								newfields=fields;
								fields=fieldsbak;
								newrecordSize=recordSize;
								recordSize=recordSizebak;
								defaultCache=defaultCachebak;
							}
							delete val;
						}
					}
				}
				x->putValue(new Buffer("_node",6),new htmlBuffer("_next"));
			}
			if((changed==0) && (newfields!=0)){ // look for deleted fields
				Field *f;
				for(sf=fields;sf!=0;sf=(SField*)f->next){
					f=*sf;
					SField* nf;
					Field *cf;
					for(nf=newfields;nf!=0;nf=(SField*)cf->next){
						cf=*nf;
						if(stricmp(cf->fieldName,f->fieldName)==0)
							break;
					}
					if(nf==0){
						if((f->flags&SYSTEM)==0){
							changed=1; // field deleted
							break;
						}
					}
				}
			}
			Table *back=0;
			int dbt=getTotal();
			int newtable=0;
			x->putValue(new Buffer("_node",6),new htmlBuffer("_root"));
			val=x->getValue("_attribute(maxrecords)");
			int nmax=-1;
			if(val && dbf){
				nmax=atoi(*val);
				if(nmax>0){
					char *b=dbf->getHeader();
					int *nf = (int*) b;
					nf++;
					if(*nf!=nmax && dbt>nmax){
						changed=1;
					}
				}
			}
			delete val;
			if(changed>0){
				back=rename();
				if(back)
					cleanupFieldList();
				else{
					newtable=1;
				}
				defaultCache=newdefaultCache;;
				fields=newfields;
				recordSize=newrecordSize;
				createTableFile();
				char *b=dbf->getHeader();
				int *nf = (int*) b;
				nf++;
				*nf=nmax;
				dbf->putHeader();
				maxRecords=nmax;
			}
			if(back){
				back->copyTo(this,dbt);
				delete back;
			}else{
				if(newtable==0){
					fields=newfields;
					cleanupFieldList();
					fields=fieldsbak;
					delete newdefaultCache;
				}
			}
			val=x->getValue("_attribute(modify)");
			if(val){
				if(stricmp(*val,"no")==0){
					dbf->setNoModify();
				}
				delete val;
			}
			editLock->release();
			release();
		}
	}
	return 0;
}


/*

int Table::makeTable(xmlObject* x)
{
	htmlBuffer *val=x->getValue("Field(00)");
	if(val && (fields==0)){
		int nf=atoi(*val);
		delete val;
		if(nf>0){
			while(fields){
				SField* sf = fields;
				fields = (SField *)(((Field *)*sf) ->next);                            
				delete sf;
			}
			delete defaultCache;
			defaultCache=0;
			x->putValue(new Buffer("_node",6),new htmlBuffer("Field"));
			for(int i=0;i<nf;++i){
				val=x->getValue("_attribute(name)");
				if(val){
					char fieldName[40];
					strcpy(fieldName,*val);
					delete val;
					val=x->getValue("_attribute(size)");
					int nsize=1;
					if(val){
						nsize=atoi(*val);
						delete val;
					}
					val=x->getValue("_attribute(dim)");
					int ndim=1;
					if(val){
						ndim=atoi(*val);
						delete val;
					}
					val=x->getValue("_attribute(type)");
					if(val){
						int nflags=NORMAL;
						int ntype=0;
						if(stricmp(*val,"String")==0)
							ntype=CHAR_TYPE;
						else{
							nsize=1;
							if(stricmp(*val,"TEXT")==0)
								ntype=FILE_TYPE;
							else
								if(stricmp(*val,"IMAGE")==0){
									ntype=FILE_TYPE;
									nflags=BINARY_DATA;
								}else
									if(stricmp(*val,"TIME")==0)
										ntype=TIME_TYPE;
									else
										if(stricmp(*val,"Numeric")==0)
											ntype=INT_TYPE;
										else
										if(stricmp(*val,"RealNumber")==0)
											ntype=REAL_TYPE;
										else{
											char* tmp=*val;
											if(*tmp==':'){
												ntype=INDEX_TYPE;
												int n=strlen(fieldName);
												fieldName[n++]='(';
												strncpy(fieldName+n,tmp+1,15);
												fieldName[n+15]=0;
												n=strlen(fieldName);
												fieldName[n++]=')';
												fieldName[n++]=0;
											}
										}
						}
						delete val;
						if((val=x->getValue("_attribute(mandatory)"))!=0){
							if(stricmp(*val,"yes")==0 || stricmp(*val,"true")==0)
								nflags|=MANDATORY;
							delete val;
						}
						if((val=x->getValue("_attribute(unique)"))!=0){
							if(stricmp(*val,"yes")==0 || stricmp(*val,"true")==0)
								nflags|=UNIQUE;
							delete val;
						}
						if((val=x->getValue("_attribute(local)"))!=0){
							if(stricmp(*val,"yes")==0 || stricmp(*val,"true")==0)
								nflags|=LOCAL;
							delete val;
						}
						if((val=x->getValue("_attribute(binary)"))!=0){
							if(stricmp(*val,"yes")==0 || stricmp(*val,"true")==0)
								nflags|=BINARY_DATA;
							delete val;
						}
						val=x->getValue("default");
						if (nsize && ndim){
							char *s=0;
							if(val)
								s=*val;
							addField(fieldName,ntype,nsize,ndim,nflags,s);
						}
						delete val;
					}
				}
				x->putValue(new Buffer("_node",6),new htmlBuffer("_next"));
			}
			createTableFile();
			x->putValue(new Buffer("_node",6),new htmlBuffer("_root"));
			val=x->getValue("_attribute(maxrecords)");
			if(val){
				maxRecords=atoi(*val);
				char *b=dbf->getHeader();
				int *nf = (int*) b;
				nf++;
				*nf=maxRecords;
				dbf->putHeader();
				delete val;					
			}
		}
	}
	return 0;
}

*/

int Table::makeTable(htmlBuffer* hdrInfo)
{
	SField *rfields=0;
	if(hdrInfo==0)
		return 0;
	char *hdbuff=*hdrInfo;
	char *b=hdbuff;
	int nf = *((int*) b);
	b+=sizeof(int);
	int validated=0;
	int recLim=-1;
	SField *sf,*rf;
	Field *f,*lfield=0;
	if(nf < MAXFIELDS){
		recLim=*((int*)b);
		b+=sizeof(int);
		int i=0;
		for(;i<nf;++i){   
			tableDef *df=(tableDef*)b;
			b+=sizeof(tableDef);
			sf = new SField();
			f=*sf;
			memset(f,0,sizeof(Field));
			strcpy(f->fieldName,df->fieldName);
			f->flags=df->flags;
			f->type=df->type;
			f->size=df->size;
			f->dim=df->dim;
			f->next = 0;
			if(df->defaultValue)
				f->defaultValue=hdbuff+df->defaultValue;
			else
				f->defaultValue=0;
			if(rfields==0){
				rfields=sf;
				lfield=f;
			}else{
				lfield->next=sf;
				lfield=f;
			}
			int ok=0;
			int fl=strlen(f->fieldName);
			if(fl > 0 && fl < 32){
				if(f->type > 0 && f->type < 5)
					if(f->flags >= 0 && f->flags < 32)
						if(f->size > 0 && f->dim > 0)
							ok=1;
			}
			if(ok==0)
				break;
		}
		if(nf==i && i > 0)
			validated=1;
    }
	if(exists()){
		sf=rfields;
		Field *x;
		for(rf=fields;rf && sf;rf=(SField*)x->next){
			x=*rf;
			f=*sf;
			if((stricmp(f->fieldName,x->fieldName)==0) &&
				(x->flags==f->flags) && (x->type==f->type) && (x->size==f->size) && (x->dim==f->dim)){
				sf=(SField*)f->next;
			}else
				break;
		}
		if((sf==rf) && (nf > 0) && recLim==maxRecords)
			validated=2;
		else
			validated=0;
	}
	if(validated==1){
		recordSize=headerSize=0;
		fields=rfields;
		maxRecords=recLim;
		getRecordSize();
		Buffer *db = new Buffer(recordSize);
		b=*db;
		dbf = new TableFile(*name,dbl,recordSize,headerSize);
		Buffer *hd=new Buffer(headerSize);
		char *hdr=*hd;
		char *hds=*hd;
		*((int*)hdr)=nFields;
		hdr+=sizeof(int);
		*((int*)hdr)=maxRecords;
		hdr+=sizeof(int)+FIELDSIZE*nFields;
		sf = fields;
		int offset=recordSize;
		while(sf){
			f = *sf;
			hdr-=FIELDSIZE;
			offset -= getFieldSize(f);
			f->offset=offset+sizeof(char);
			f->hdOffset=hdr-hds;
			memcpy(hdr,f,FIELDSIZE);
			sf=(SField*)f->next;
			if((f->defaultValue==0) || (stricmp(f->fieldName,sORIGIN)==0))
				f->defaultValue=nullString;
			memcpy(b+getFieldOffset(f),f->defaultValue,f->size*elementSize(f->type));
			f->defaultValue = b+getFieldOffset(f);
		}
		dbf->putHeader(hds,headerSize);
		dbf->add(b);
		dbf->flush();
		defaultCache=db;
		delete hd;
    }else{
		for(sf=rfields;sf!=0;sf=rf){
			rf=(SField*)(((Field*)*sf)->next);
			delete sf;
		}
    }
	deleteHtmlBuffer(hdrInfo);
	return validated;
}



#define CHANGE_CTOF 1
#define CHANGE_FTOC 2
#define CHANGE_SIZE  4
#define CHANGE_DIM   8
#define CHANGE_MANDATORY    32

void Table::hidePSWD()
{
	Field *f=getField(sPSWD);
	if(f){
		if((f->flags&HIDDEN)==0){
			f->flags&=~SYSTEM;
			f->flags|=HIDDEN;
			char*b=dbf->getHeader();
			b+=f->hdOffset;
			memcpy(b,f,FIELDSIZE);
			dbf->putHeader();
        }
	}
}

void Table::addFields(Field *f,Field *nf,int add)
{
    SField* jf=fields;
    SField* tf;
    fields=0;
    Field* l;
    while(jf!=0){
		l=*jf;
		if((l->flags&SYSTEM) && nf && add){
			l=nf;
			tf=0;
			add=0;
		}else{
			tf=jf;
			jf=(SField*)l->next;
			if(f==l && add==0)
				l=nf;
		}
ADDF:
		if(l!=0){
			if(stricmp(l->fieldName,sMSGID) && stricmp(l->fieldName,sQUEUEID) && stricmp(l->fieldName,sRECID) && stricmp(l->fieldName,"_origin") && stricmp(l->fieldName,"_originID")){
				if(l->type==INDEX_TYPE){
					char tmp[64];
					snprintf(tmp,64,"%s(%s)",l->fieldName,l->tableName);
					addField(tmp,l->type,l->size,l->dim,l->flags,l->defaultValue,l!=nf);
				}else
					addField(l->fieldName,l->type,l->size,l->dim,l->flags,l->defaultValue,l!=nf);
			}
		}
		if(add){
			if(f==l){
				l=nf;
				add=0;
				goto ADDF;
			}else
				if(tf==0)
					break;
		}
		delete tf;
	}
	while(jf!=0){
		l=*jf;
        tf=jf;
        jf=(SField*)l->next;
		delete tf;
	}
}




int Table::modifyField(genericObject* form,Field* f)
{
	SField *sf=mkField(form);
	if(sf==0)
		return 0;
	int r=modifyField((Field*)*sf,f);
	delete sf;
	return r;
}

int Table::modifyField(Field *nf,Field* f)
{
	int change=0;
	if(stricmp(nf->fieldName,f->fieldName)){
		if(nf->type==FILE_TYPE && f->type==FILE_TYPE){
			int i;
			Buffer *path=new Buffer((i=strlen(*name))+strlen(f->fieldName)+20);
			char *p=*path;
			strcpy(p,*name);
			for(;i>0;--i){
				if(p[i]=='.')
					break;
			}
			if(i>0){
				i++;
				strcpy(p+i,f->fieldName);
				Buffer *newpath=new Buffer(path->getSize());
				char* np=*newpath;
				strncpy(np,p,i);
				strcpy(np+i,nf->fieldName);
				int success;
				FileMove(p,np,success);
				if(success){
					strcpy(f->fieldName,nf->fieldName);
					change=1;
				}
				delete newpath;
			}
			delete path;			
		}else{
			strcpy(f->fieldName,nf->fieldName);
			change=1;
		}
	}
	if((nf->flags&LOCAL) != (f->flags&LOCAL)){
		f->flags&=~LOCAL;
		f->flags|=nf->flags&LOCAL;
		change=1;
	}
	if((nf->flags&MANDATORY)==0){
		if(f->flags&MANDATORY){
			f->flags&=~MANDATORY;
			change=1;
		}
	}
	if((nf->flags&UNIQUE)==0){
		if(f->flags&UNIQUE){
			f->flags&=~UNIQUE;
			change=1;
		}
	}
	if(nf->flags&BINARY_DATA){
		if((f->flags&BINARY_DATA)==0){
			f->flags|=BINARY_DATA;
			change=1;
		}
	}else{
		if(f->flags&BINARY_DATA){
			f->flags&=~BINARY_DATA;
			change=1;
		}
	}
	if(nf->type==INT_TYPE || nf->type==TIME_TYPE){
		if(f->type!=nf->type)
			if(f->type==INT_TYPE || f->type==TIME_TYPE || f->type==INDEX_TYPE){
				f->type=nf->type;
				change=1;
			}
	}
	if(change){
		char *b=dbf->getHeader();
		b+=f->hdOffset;
		memcpy(b,f,FIELDSIZE);
		dbf->putHeader();
		change=0;
		getTableInfo(1);
	}
	if(nf->type==INT_TYPE){
			if(f->type==REAL_TYPE){
				f->type=nf->type;
				change=1;
			}
	}
	if(nf->type==REAL_TYPE){
			if(f->type==INT_TYPE || f->type==CHAR_TYPE){
				f->type=nf->type;
				change=1;
			}
	}
	if(nf->type==INDEX_TYPE){
			if(f->type==INT_TYPE){
				f->type=nf->type;
				change=1;
			}
	}
	if(nf->type==CHAR_TYPE){
			if(f->type==REAL_TYPE){
				f->type=nf->type;
				nf->size=32;
				change=1;
			}
	}
	if(f->type==INT_TYPE){
		if(nf->type!=f->type){
			change=1;
			if(nf->type==CHAR_TYPE)
				nf->size=16;
        }
	}
	if(f->type==CHAR_TYPE || f->type==FILE_TYPE){
		if(nf->type!=f->type){
			if(nf->type==CHAR_TYPE)
				change=CHANGE_FTOC;
			else
				if(nf->type==INT_TYPE){
					if(f->type!=FILE_TYPE){
						change=1;
					}
				}
				else{
					if(nf->type==FILE_TYPE){
						nf->type=NEWFILE_TYPE;
						change=CHANGE_CTOF;
					}
				}
		}
	}
	if(nf->size!=f->size){
		if(f->type==CHAR_TYPE && nf->type==CHAR_TYPE)
			change|=CHANGE_SIZE;
	}
	if(nf->dim!=f->dim)
		change|=CHANGE_DIM;
	if(f->flags!=nf->flags){
		if((f->flags&MANDATORY)!=(nf->flags&MANDATORY))
			change|=CHANGE_MANDATORY;
	}
	if(change){
		editLock->lock();
		int dbt=getTotal();
		Table *back=rename();
		if(back==0){
			editLock->release();
			return 0;
		}
		nFields=0;
		headerSize=0;
		Buffer *dvbuff=defaultCache;
		defaultCache=0;
		recordSize=0;
		fileInfoSize=sizeof(FILEINFO);
		addFields(f,nf);
		createTableFile();
		back->copyTo(this,dbt);
		delete back;
		delete dvbuff;
		editLock->release();
	}
	return 1;
}


void Table::setBinType(int n)
{
	Field *f;
	SField *sf;
	if(n){
		for(sf=fields;sf!=0;sf=(SField*)f->next){
			f=*sf;
			if(f->type==FILE_TYPE)
				f->type=BIN_TYPE;
			else
				if(f->type==NEWFILE_TYPE)
					f->type=FILE_TYPE;
		}
	}else{
		char *tmpHeader=dbf->getHeader();
		for(sf=fields;sf!=0;sf=(SField*)f->next){
			f=*sf;
			if(f->type==BIN_TYPE){
				f->type=FILE_TYPE;
				memcpy(tmpHeader+f->hdOffset,f,FIELDSIZE);
				dbf->bufferedPutHeader();
			}
		}
		dbf->flushDat();
	}
}


void Table::copyTo(Table* tbl, int dbt)
{
	if(exists()==0)
		return ;
	int max=dbf->getNewRecordNo();
	int failed=0;
	int copied=0;
	Field *f;
	SField *sf;
	setBinType(1);
	tbl->setBinType(1);
	for(sf=fields;sf!=0;sf=(SField*)f->next){
		f=*sf;
		Field *nf=tbl->getField(f->fieldName);
		if(nf!=0){
			if(nf->type==CHAR_TYPE && f->type==BIN_TYPE)
				f->type=FILE_TYPE;
		}
	}
	int p=getNext(0,1);
	if(p==0)
		p=max;
	tbl->dbf->setUrecId(dbf->incUrecId());
	tbl->dbf->skip(p);
	int i;
	for(i=p;i<max;++i){
		if(!exists(i)){
			tbl->dbf->skip(0);
		}else{
			htmlObject *nv=new htmlObject();
			for(sf=fields;sf!=0;sf=(SField*)f->next){
				f=*sf;
				htmlBuffer *z=getFieldValue(i,(char*)0,f);
				if(z){
					nv->putValue(new Buffer(f->fieldName,strlen(f->fieldName)+1),z);
				}
			}
			if(tbl->insertRow(nv,2)!=i){
				tbl->dbf->skip(0);
				failed++;
			}else{
				copied++;
			}
			delete nv;
			DeleteCachedRecord(i);
			letCacheClear();
//			delRecordFromCache(i);
		}
	}
	tbl->dbf->skip(max);
	tbl->setBinType(0);
	setBinType(0);
	tbl->dbf->flushDats(1);
	for(i=p;i<max;++i){
		if(exists(i)){
				tbl->dbf->setRecordTime(i,dbf->getCreatedTime(i),dbf->getModifiedTime(i));
		}
	}
	if(dbt!=copied){
		printf("*********** ERROR WHILE COPYING TABLE %s , total records =%d / copied=%d **********\n",tableName,dbt,copied);
	}
}


int Table::addField(genericObject* form,Field *f)
{
	SField *sf=mkField(form);
	if(sf==0)
		return 0;
	editLock->lock();
	Field *nf=*sf;
	int dbt=getTotal();
	if(nf->flags&UNIQUE || nf->flags&MANDATORY){
		if(dbt>1){
			delete sf;
			editLock->release();
			return 0;
		}
	}
	Table *back=rename();
	if(back==0){
		delete sf;
		editLock->release();
		return 0;
	}
	nFields=0;
	headerSize=0;
	Buffer *dvbuff=defaultCache;
	defaultCache=0;
	recordSize=0;
	fileInfoSize=sizeof(FILEINFO);
	addFields(f,nf,1);
	delete sf;
	createTableFile();
	back->copyTo(this,dbt);
	delete back;
	delete dvbuff;
	editLock->release();
	return 1;
}


int Table::backupTable()
{
	int dbt=getTotal();
	editLock->lock();
	Table *back=rename();
	if(back!=0){
		nFields=0;
		headerSize=0;
		Buffer *dvbuff=defaultCache;
		defaultCache=0;
		recordSize=0;
		fileInfoSize=sizeof(FILEINFO);
		addFields();
		createTableFile();
		back->copyTo(this,dbt);
		delete back;
		delete dvbuff;
	}
	editLock->release();
	return (back!=0);
}

void rmChild(char* dbname,char*tbl,char*child);

int Table::deleteField(Field* f)
{
	int dbt=getTotal();
	editLock->lock();
	Table *back=rename();
	if(back!=0){
		nFields=0;
		headerSize=0;
		Buffer *dvbuff=defaultCache;
		defaultCache=0;
		recordSize=0;
		if(f->type==INDEX_TYPE){
			if(isChild(f->tableName)==0){
				rmChild(dbname,f->tableName,tableName);
			}
		}
		addFields(f);
		createTableFile();
		back->copyTo(this,dbt);
		delete back;
		delete dvbuff;
    }
	editLock->release();
	return (back!=0);
}

SField* Table::mkField(genericObject *form)
{
	SField *nf=new SField;
	Field *n=*nf;
        memset(n,0,sizeof(Field));
	char *val;
	if(((val=form->showValue("fieldname"))==0) || (*val==0)){
		delete nf;
		return 0;
	}
	strcpy(n->fieldName,val);
	if((val=form->showValue("size"))==0){
		delete nf;
		return 0;
	}
	n->size=atoi(val);
	if((val=form->showValue("dim"))==0){
		delete nf;
		return 0;
	}
	n->dim=atoi(val);
	if((val=form->showValue("type"))==0){
		delete nf;
		return 0;
	}
	n->flags=0;
	if(stricmp(val,"string")==0)
		n->type=CHAR_TYPE;
	else{
		n->size=1;
		if(stricmp(val,"TEXT")==0)
			n->type=FILE_TYPE;
		else
		if(stricmp(val,"IMAGE")==0){
			n->type=FILE_TYPE;
			n->flags=BINARY_DATA;
		}else
		if(stricmp(val,"TIME")==0)
			n->type=TIME_TYPE;
		else
		if(stricmp(val,"Numeric")==0)
			n->type=INT_TYPE;
		else
		if(stricmp(val,"RealNumber")==0)
			n->type=REAL_TYPE;
		else
		if(strnicmp(val,"RELATION->",10)==0){
			n->type=INDEX_TYPE;
			strcpy(n->tableName,val+10);     
		}
	}
	htmlBuffer* flags=form->getValue("flags");
	htmlBuffer *t;
	while(flags){
		char *fv=*flags;
		switch(*fv){
		case 'M':
			n->flags|=MANDATORY;
			break;
		case 'U':
			n->flags|=UNIQUE;
			break;
		case 'K':
			n->flags|=BINARY_DATA;
			break;
		case 'L':
			n->flags|=LOCAL;
			break;
		case 'H':
			n->flags|=HIDDEN;
			break;
		default:
			break;
		}
		t=flags;
		flags=flags->next;
		delete t; 
	}
	n->defaultValue=form->showValue("dv");
	return nf;
}

void closeTable(char*);

Table* Table::rename()
{
	if(dbf!=0){
		lock();
		dbf->flushDats(1);
		initTable();
		int dbt=getTotal();
		int success=0;
		char path[512];
		char tblname[256];
		snprintf(tblname,256,"_%s.data",tableName);
		strcpy(path,*name);
		int pl=strlen(path);
		for( ; pl > 0 ; pl-- ) {
			if(path[pl]==FSLASH || path[pl]==SLASH){
				break;
			}
		}
		if(pl>0 && (stricmp(path+pl+1,tblname+1)==0)){
			strcpy(path+pl+1,tblname);
			closeTable(path);
			delete dbf;
			dbf=0;
			FileMove(*name,path,success);
			if(success==0){
				File *f=new File(path);
				success=f->deleteFile();
				delete f;
				FileMove(*name,path,success);
			}
			if(success){
				Table *back=new Table(path);
				if((back->exists()==0) || exists() || (back->getTotal()!=dbt)){
					delete back;
					back=0;
				}else{
					release();
					return back;
				}
			}
		}
		snprintf(path,512,"Error creating backup : %s\r\n",(char*)*name);
		caravanlog(path);
		release();
	}
	return 0;
}




/*
Table* Table::rename()
{
	lock();
	dbf->flushDats(1);
	initTable();
	int dbt=getTotal();
	int success=0;
	char path[512];
	char tblname[256];
	snprintf(tblname,256,"_%s.data",tableName);
	strcpy(path,*name);
	int pl=strlen(path);
	for( ; pl > 0 ; pl-- ) {
		if(path[pl]==FSLASH || path[pl]==SLASH){
			break;
		}
	}
	if(pl>0 && (stricmp(path+pl+1,tblname+1)==0)){
		strcpy(path+pl+1,tblname);
		closeTable(path);
		path[pl]=0;
		for(int y=0;y<MAXSELECTION;++y){
			if(cachedSelection[y]){
				delete cachedSelection[y];
				cachedSelection[y]=0;
			}
		}
		delete dbf;
		dbf=0;
		if(caches){
			CacheData *x=*caches;
			if(x!=0){
				for(int n=caches->getTotal()-1;n>=0;n--)
					delete x[n].hold;
				caches->init();
			}
		}
		finder *f=new finder(path);
		int found=0;
		snprintf(tblname,256,"%s.*",tableName);
		if(f->findAll(tblname)){
			do{
				found++;
				char *s=f->getFullName();
				for (pl=strlen(s);pl>0 ;pl-- ) {
					if(s[pl]==FSLASH || s[pl]==SLASH)
						break;
				}
				if (pl==0 || strnicmp(path,s,pl)){
					delete f;
					initTable();
					release();
					return 0;
				}
				path[pl++]=FSLASH;
				path[pl]='_';
				strcpy(path+pl+1,s+pl);
				if(f->isDirectory()){
					finder *d=new finder(path);
					if(d->findFile("*")){
						do{
							FileDelete(d->getFullName(),success);
							if(success){
								finder *f=new finder(path);
								if(f->findAll(d->getName()))
									success=0;
								delete f;
							}
						}while(success && d->find());
					}
					delete d;
					DirectoryDelete(path,success);
				}else{
					FileDelete(path,success);
					if(success){
						path[pl-1]=0;
						finder *d=new finder(path+pl+1);
						if(d->findAll(f->getName()))
							success=0;
						delete d;
					}
				}
				if(!success){
					delete f;
					initTable();
					release();
					return 0;
				}
			}while(f->find());
		}
		typedef struct fname{
			char oldname[256];
			char newname[256];
			struct fname* next;
			Buffer *bf;
		}FNAME;
		FNAME* fnames=0;
		if(found && f->findAll(tblname)){
			do{
				char *s=f->getFullName();
				for (pl=strlen(s);pl>0 ;pl-- ) {
					if(s[pl]==FSLASH || s[pl]==SLASH)
						break;
				}
				if(pl>0){
					strncpy(path,s,++pl);
					path[pl]='_';
					strcpy(path+pl+1,s+pl);
					FileMove(s,path,success);
				}else
					success=0;
				if (success==0){
					while(fnames){
						FileMove(fnames->newname,fnames->oldname,success);
						FNAME* tmp=fnames->next;
						delete fnames->bf;
						fnames=tmp;
					}
					initTable();
					delete f;
					release();
					return 0;
				}else{
					Buffer *fn=new Buffer(sizeof(FNAME));
					FNAME *tn=(FNAME*)((char*)*fn);
					tn->next=fnames;
					fnames=tn;
					tn->bf=fn;
					strcpy(tn->oldname,s);
					strcpy(tn->newname,path);
				}
			}while(f->find());
		}
		while(fnames){
			FNAME* tmp=fnames->next;
			delete fnames->bf;
			fnames=tmp;
		}
		delete f;
		if(path[pl++]=='_'){
			snprintf(path+pl,256-pl,"%s.data",tableName);
			Table *back=new Table(path);
			if( back->exists()==0 || exists() || back->getTotal()!=dbt){
				delete back;
				back=0;
			}
			release();
			return back;
		}
   }
   release();
   return 0;
}



Table* Table::rename()
{
	lock();
	dbf->flushDats(1);
	initTable();
	int dbt=getTotal();
	int success=0;
	char path[512];
	char tblname[256];
	snprintf(tblname,256,"_%s.data",tableName);
	strcpy(path,*name);
	int pl=strlen(path);
	for( ; pl > 0 ; pl-- ) {
		if(path[pl]==FSLASH || path[pl]==SLASH){
			break;
		}
	}
	if(pl>0 && (stricmp(path+pl+1,tblname+1)==0)){
		strcpy(path+pl+1,tblname);
		closeTable(path);
		path[pl]=0;
		for(int y=0;y<MAXSELECTION;++y){
			if(cachedSelection[y]){
				delete cachedSelection[y];
				cachedSelection[y]=0;
			}
		}
		delete dbf;
		dbf=0;
		if(caches){
			CacheData *x=*caches;
			if(x!=0){
				for(int n=caches->getTotal()-1;n>=0;n--)
					delete x[n].hold;
				caches->init();
			}
		}
		finder *f=new finder(path);
		int found=0;
		snprintf(tblname,256,"%s.*",tableName);// find all files/folders like tablename.* and delete the corresponding _tablename.*
		if(f->findAll(tblname)){
			do{
				found++;
				char *s=f->getFullName();
				for (pl=strlen(s);pl>0 ;pl-- ) {
					if(s[pl]==FSLASH || s[pl]==SLASH){
						break;
					}
				}
				if ((pl==0) || (strnicmp(path,s,pl)!=0)){
					delete f;
					initTable();
					release();
					return 0;
				}
				path[pl]=0;
				finder *df=new finder(path); // findfile/directory
				snprintf(path+pl++,512-pl,"%c_%s",FSLASH,s+pl);
				if(df->findAll(path+pl)){
					if(df->isDirectory()){
						finder *d=new finder(path);
						success=1;
						if(d->findFile("*")){
							do{
								FileDelete(d->getFullName(),success);
								if(success){
									finder *f=new finder(path);
									if(f->findAll(path+pl))
										success=0;
									delete f;
								}
							}while(success && d->find());
						}
						delete d;
						if(success)
							DirectoryDelete(path,success);
					}else{
						FileDelete(path,success);
						if(success){
							path[pl-1]=0;
							finder *d=new finder(path);
							if(d->findAll(path+pl))
								success=0;
							delete d;
						}
					}
				}
				delete df;
				if(!success){
					delete f;
					printf("Error: cannot delete %s\r\nTable Cannot be modified\r\n",path);
					initTable();
					release();
					return 0;
				}
			}while(f->find());
		}
		typedef struct fname{
			char oldname[256];
			char newname[256];
			struct fname* next;
			Buffer *bf;
		}FNAME;
		FNAME* fnames=0;
		if(found && f->findFile(tblname)){
			do{
				char *s=f->getFullName();
				for (pl=strlen(s);pl>0 ;pl-- ) {
					if(s[pl]==FSLASH || s[pl]==SLASH)
						break;
				}
				if(pl>0){
					strncpy(path,s,++pl);
					path[pl]='_';
					strcpy(path+pl+1,s+pl);
					FileMove(s,path,success);
				}else
					success=0;
				if (success==0){
					while(fnames){
						FileMove(fnames->newname,fnames->oldname,success);
						FNAME* tmp=fnames->next;
						delete fnames->bf;
						fnames=tmp;
					}
					initTable();
					delete f;
					release();
					return 0;
				}else{
					Buffer *fn=new Buffer(sizeof(FNAME));
					FNAME *tn=(FNAME*)((char*)*fn);
					tn->next=fnames;
					fnames=tn;
					tn->bf=fn;
					strcpy(tn->oldname,s);
					strcpy(tn->newname,path);
				}
			}while(f->find());
		}
		while(fnames){
			FNAME* tmp=fnames->next;
			delete fnames->bf;
			fnames=tmp;
		}
		delete f;
		if(path[pl++]=='_'){
			snprintf(path+pl,256-pl,"%s.data",tableName);
			Table *back=new Table(path);
			if( back->exists()==0 || exists() || back->getTotal()!=dbt){
				delete back;
				back=0;
			}
			release();
			return back;
		}
   }
   release();
   return 0;
}

void Table::list()
{
   Field *f;
   int uniques=0;
   for(SField* sf=fields;sf!=0;sf=(SField*)f->next){
      f=*sf;
   uniques=0;
   int tt=dbf->getTotal();
   for(int i=1;i<tt;++i){
      int rec=(*dbf)[i];
      char *newRec=getRecordCached(rec);
      recordInfo* node=(recordInfo*)(newRec+f->offset);
      if(node->centerWeight!=-1)
         uniques++;
      if(node->balance > 1 || node->balance <-1){
         printf("(%d) : %s %d p%d l%d r%d c%d b%d : Balance is wrong\n",tt,f->fieldName,rec,node->parent,node->left,node->right,node->center,node->balance);
         exit (0);
         }
      if(node->right){
         char *tmp=getRecordCached(node->right);
	 if(tmp==0)
		printf("no right child\n");
         else{
         recordInfo* tnode=(recordInfo*)(tmp+f->offset);
         if(tnode->leftWeight+tnode->rightWeight+tnode->centerWeight+1!=node->rightWeight){
            printf("%s error in right weight\n",f->fieldName);
            SleepMilSec(3000);
            }
         if(tnode->parent!=rec)
            printf("parent of %d->right %d is %d\n",rec,node->right,tnode->parent);
         if(compare(tmp+getFieldOffset(f),newRec+getFieldOffset(f),f->type)<=0){
            printf("not valid right child\n");
            }
         }
       }
      if(node->left){
         char *tmp=getRecordCached(node->left);
	 if(tmp==0)
		printf("no left child\n");
         else{
         recordInfo* tnode=(recordInfo*)(tmp+f->offset);
         if(tnode->leftWeight+tnode->rightWeight+tnode->centerWeight+1!=node->leftWeight){
            printf("%s error in left weight\n",f->fieldName);
            SleepMilSec(3000);
            }
         if(tnode->parent!=rec)
            printf("parent of %d->left %d is %d\n",rec,node->left,tnode->parent);
         if(compare(tmp+getFieldOffset(f),newRec+getFieldOffset(f),f->type)>=0){
            printf("not valid left child\n");
            }
         }
      }
      if(node->center){
         if(node->centerWeight>0){
            int c=node->centerWeight;
            int cc=node->center;
            int r=rec;
            while(cc){
               c--;
               char *tmp=getRecordCached(cc);
               if(tmp==0){
		printf("no center child\n");
                break;
                }
               else{
                recordInfo* tnode=(recordInfo*)(tmp+f->offset);
                if(tnode->parent!=r)
                   printf("parent not ok\n");
                r=cc;
                cc=tnode->center;
                }
               }
            if(c || cc)
                printf("%s %d %d error in center height\n",f->fieldName,c,cc);
            
         }
         char *tmp=getRecordCached(node->center);
	 if(tmp==0)
		printf("no center child\n");
         else{
         recordInfo* tnode=(recordInfo*)(tmp+f->offset);
         if(tnode->parent!=rec)
            printf("parent of %d->center %d is %d\n",rec,node->center,tnode->parent);
         if(compare(tmp+getFieldOffset(f),newRec+getFieldOffset(f),f->type)){
            printf("values not equal\n");
            }
         }
      }
      if(node->parent){
         char *tmp=getRecordCached(node->parent);
	 if(tmp==0)
		printf("no parent\n");
         else{
         recordInfo* tnode=(recordInfo*)(tmp+f->offset);
         if(tnode->right==rec){
          if(compare(tmp+getFieldOffset(f),newRec+getFieldOffset(f),f->type)>=0)
            printf("p not valid right child\n");
            }else
				if(tnode->left==rec){
          if(compare(tmp+getFieldOffset(f),newRec+getFieldOffset(f),f->type)<=0)
            printf("p not valid left child\n");
            }else
				if(tnode->center==rec){
          if(compare(tmp+getFieldOffset(f),newRec+getFieldOffset(f),f->type))
            printf("values not equal\n");
				}else{
					printf("parent link not ok\n");
				}
         }
         }else{
            if(f->root){
               if(f->root!=rec){
                char *tmp=getRecordCached(f->root);
    	        if(tmp==0)
		   printf("%s no root\n",f->fieldName);
               else{
                  recordInfo* tnode=(recordInfo*)(tmp+f->offset);
                  if(tnode->centerWeight+tnode->rightWeight+tnode->leftWeight!=dbf->getTotal()-2)
;//                     printf("error in weightage at %s \n",f->fieldName);
                  else
                     printf("ok\n");
                  if(!(tnode->parent==0  && node->left==0 &&  node->right==0 && node->center==0))
                    printf("%s not valid root\n",f->fieldName);
                }
             }else{
                char *tmp=getRecordCached(f->root);
    	        if(tmp==0)
		   printf("%s no root\n",f->fieldName);
               else{
                  recordInfo* tnode=(recordInfo*)(tmp+f->offset);
                  if(tnode->centerWeight+tnode->rightWeight+tnode->leftWeight!=dbf->getTotal()-2)
;//                     printf("error in weightage at %s \n",f->fieldName);
                }
             }
           }
          }
      }
    if(f->root){
     if(uniques!=f->unodes)
      printf("%s:uniques not ok found=%d total=%d \n",f->fieldName,uniques,f->unodes);
    }
   }
}

memcpy(oldData+getFieldOffset(f),c+getFieldOffset(f),i*f->size*elementSize(f->type));


 

					if(((f->flags&BINARY_DATA)==0) &&
						((f->type==CHAR_TYPE) || (f->type==FILE_TYPE))){
						snprintf(fieldId,64,"%s.%s.%s",dbname,tableName,f->fieldName);
						wb=wbs[wbt++]=new WordBasket(fieldId);
						v=getFieldValue(recordNo,0,f);
						while(v){
							wb->putWords(v,OLDWORD);
							htmlBuffer *t=v;
							v=v->next;
							delete t;  
						}
					}
*/


/*
Void Table::createSubTable(Buffer *subset,LinkedBuffer *fiedNames)
{
	int n=subset->getSize()/sizeof(int);
	LinkedBuffer* f=fieldNames;
	int fieldNos=0;
	for(;f!=0;f=f->next)
	 fieldNos++;
	Buffer *b=new Buffer(n*sizeof(int)*(1+fieldNos*3));

	for(int i=0;i<n;++i){
	 insert(b,i,subs[i]);
	}
}



Selection* Table::getSelection(Buffer* query,Buffer* subset,int addsubset)

{
	queryStruct* qx;
	LinkedBuffer *fs=0;
	Buffer* qbuff=getQueryList(query,&fs);
	Buffer *b;
	int ts=0;
	if(qbuff){
		qx=(queryStruct*) ((char*)*qbuff);
		ts=qbuff->getSize()/sizeof(queryStruct) - 1;
	}
	if((qbuff==0) || ((qx[0].m==INCLUDE_ALL) && (ts==1) && (qx[1].f==0))){
		delete qbuff;
		deleteLinked(fs);
		if(subset){
			Selection *s=new Selection();
			s->putStore(subset);
			return s;
		}
		return qbuff?ALLSELECTED:0;
	}
	int sin=0;
	int qi=0;
	Selection  *selections[128];
	memset(selections,0,sizeof(selections));
	int alt=-1;
	int sortby=-1;
	int likes=0;
	if(qx[0].m & INCLUDE_ALL){
		if(qx[1].f){
			Selection *s =0;
			if(qx[1].f->type==INDEX_TYPE && qx[1].rel){
				int l;
				Buffer *buff=new Buffer(l=(qx[1].rel->getSize()+12));
				buff->setSize(snprintf(*buff,l-1,"order by %s",(char*)*(qx[1].rel))+1);
				s=selectByRelation(qx[1].f,buff);
				if(s==0){
					deleteLinked(fs);
					delete qbuff;
					return 0;
				}
			}else{
				if(fs==0){
					Buffer *b=getSelectionFromCache(qx[1].f,FROMTO,0,0);
					if(b!=0){
						s=new Selection();
						s->putStore(b);
					}
				}
				if(s==0)
					s=new Range(this,0,0,qx[1].f,FROMTO,fs?(qx[1].m&ORDER?-1:1):0,fs);
			}
			if(subset==0){
				s->setOrder((qx[1].m&ORDER)?-1:1);
				deleteLinked(fs);
				delete qbuff;
				return s;
			}else{
				selections[0]=s;
				sin=1;
            }
		}else{
            if(subset!=0){
				Selection *s=new Selection();
				s->putStore(subset);
				s->setOrder((qx[1].m&ORDER)?-1:1);
				deleteLinked(fs);
				delete qbuff;
				return s;
			}
		}
	}else{
		for(qi=0;qi<ts;++qi){
			if(qx[qi].f!=0){
				if(qx[qi].rel!=0){
					if(qx[qi].f && qx[qi].f->type==INDEX_TYPE){
						Buffer *nqb=new Buffer(2048);
						char *nq=*nqb;
						char* ref=nq+nqb->getSize();
						nq+=snprintf(nq,ref-nq,"where %s %s",(char*)*qx[qi].rel,getstring(qx[qi].m));
						if(qx[qi].v){
							nq=maskCopy(nq,qx[qi].v);
						}
						delete qx[qi].v;
						delete qx[qi].rel;
						for(int i=qi+1;i<ts;++i){
							if((qx[qi].f==qx[i].f) && (qx[i].rel!=0)){
								nq+=snprintf(nq,ref-nq," %s %s %s",(qx[ts].m&AND)?"and":"or",(char*)*qx[i].rel,getstring(qx[i].m));
								if(qx[i].v){
									nq=maskCopy(nq,qx[i].v);
								}
								qx[i].f=0;
								delete qx[i].v;
								delete qx[i].rel;
							}
						}
						if(((ts==1) || (qx[ts].m&AND)) && (qx[ts].f!=0) && (qx[ts].f==qx[qi].f) && (qx[ts].rel!=0)){
							nq+=snprintf(nq,ref-nq," order by %s",(char*)*(qx[ts].rel));
							sortby=sin;
							qx[ts].f=0;
							delete qx[ts].rel;
						}
						nqb->setSize((nq-(char*)*nqb)+1);
						selections[sin]=selectByRelation(qx[qi].f,nqb);
						if(selections[sin]==0){
							selections[sin]=new Selection();
						}
						sin++;
						qx[qi].f=0;
					}
				}else{
					Buffer *from=0;
					if(qx[qi].m!=LIKE && qx[qi].m!=LIKES){
						from=qx[qi].v?getVal(*qx[qi].v,qx[qi].f):0;
						delete qx[qi].v;
						qx[qi].v=0;
					}
					else{
						if(qx[qi].m==LIKE){
							from=qx[qi].v;
							qx[qi].v=0;
						}
					}
					Buffer* to=qx[qi].to?getVal(*qx[qi].to,qx[qi].f):0;
					delete qx[qi].to;
					switch(qx[qi].m&~(EXCLUDE|UNIQ)){
					case LIKES:
						likes++;
						break;
					case LIKE:
						{	
							selections[sin]=new Selection();
							Buffer *tmp=new Buffer(64);
							if(qx[qi].f){
								snprintf(*tmp,64,"%s.%s.%s",dbname,tableName,qx[qi].f->fieldName);
								Buffer *likes=findWord(*from,*tmp);
								if(likes){
									selections[sin]->putStore(likes);
									if(alt<0)
										alt=sin;
								}
							}
							delete tmp;
							sin++;
						}
						qx[qi].f=0;
						break;
					case EQU:
						delete to;
						if(stricmp(*from,"null")==0){
							delete from;
							if((b=getSelectionFromCache(qx[qi].f,FROMTO,0,0))!=0){
								Selection *s=new Selection();
								s->putStore(b);
								selections[sin]=s;
							}
							if(selections[sin]==0)
								selections[sin]=new Range(this,0,0,qx[qi].f,FROMTO,0,0);
							qx[qi].m|=EXCLUDE;
						}else{
							if((b=getSelectionFromCache(qx[qi].f,EQU,*from,0))!=0){
								delete from;
								Selection *s=new Selection();
								s->putStore(b);
								selections[sin]=s;
							}
							if(selections[sin]==0)
								selections[sin]= new Equals(this,from,qx[qi].f);
						}
						if(qx[qi].m&EXCLUDE){
excludeSelected:
							Buffer *mx=selections[sin]->getBuffer();
							Buffer *eb;
							int *x;
							int at;
							if(subset && !addsubset){
								eb=new Buffer(*subset,subset->getSize());
								x=(int*)((char*)(*eb));
								at=eb->getSize()/sizeof(int);
							}
							else{
								eb=dbf->getValidList();
								x=(int*)((char*)(*eb));
								x++;
								at=(eb->getSize()/sizeof(int))-1;
							}
							if(at>0){
								if((mx!=0) && (selections[sin]->getTotal()>0)){
									sortList(mx);
									int mj=0;
									for(int mi=0;mi<at;++mi){
										if(findinList(mx,x[mi])==0){
											x[mj++]=x[mi];
										}
									}
									Buffer *all=eb;
									eb=(mj?new Buffer((char*)x,mj*sizeof(int)):0);
									delete all;
									delete mx;
								}
							}else{
								delete eb;
								eb=0;
							}
							delete selections[sin];
							selections[sin]=new Selection();
							if(eb)
								selections[sin]->putStore(eb);
						}else{
							if((fs!=0) && (qx[ts].rel==0 && qx[ts].f==qx[qi].f))
								qx[ts].f=0;
						}
						sin++;
						break;
					case 0:
						delete from;
						delete to;
						if((b=getSelectionFromCache(qx[qi].f,UNIQ,0,0))!=0){
							Selection *s=new Selection();
							s->setField(qx[qi].f);
							s->putStore(b);
							selections[sin]=s;
						}
						if(selections[sin]==0)
							selections[sin]=new uniqueRange(this,qx[qi].f);
						selections[sin]->setUnique();
						sin++;
						break;
					case LTE:
						qx[qi].m|=INCLUDE_TO;
					case LT:
						delete to;
						to=from;
						from=0;
						qx[qi].m&=(EXCLUDE|UNIQ|INCLUDE_TO);
						goto rangeSelect;
					case GTE:
						qx[qi].m|=INCLUDE_FROM;
					case GT:
						qx[qi].m&=(EXCLUDE|UNIQ|INCLUDE_FROM);
						delete to;
						to=0;
					case FROMTO+INCLUDE_FROM:
					case FROMTO+INCLUDE_TO:
					case FROMTO+INCLUDE_FROM+INCLUDE_TO:
					case FROMTO:
rangeSelect:
						int fresh=0;
						if((qx[ts].m&AND) && (qx[ts].f==qx[qi].f) && (qx[ts].rel==0)){
							sortby=sin;
							qx[ts].f=0;
							if(fs)
								fresh=1;
						}
						qx[qi].m|=FROMTO;
						if(fresh==0){
							char *froms=0;
							if(from)
								froms=*from;
							char *tos=0;
							if(to)
								tos=*to;
							if((b=getSelectionFromCache(qx[qi].f,(char)qx[qi].m,froms,tos))!=0){
								Selection *s=new Selection();
								s->setField(qx[qi].f);
								s->putStore(b);
								selections[sin]=s;
								delete from;
								delete to;
							}
						}
						if(selections[sin]==0){
							if(fresh)
								selections[sin]=new Range(this,from,to,qx[qi].f,(char)qx[qi].m,(qx[ts].m&ORDER?-1:1),fs);
							else
								selections[sin]=new Range(this,from,to,qx[qi].f,(char)qx[qi].m);
						}
						if(qx[qi].m&EXCLUDE){
							goto excludeSelected;
						}
						if(qx[qi].m&UNIQ)
							selections[sin]->setUnique();
						sin++;
				}
			}
		}
	  }
   }
   if(qi==0){
	   if(subset==0){
		   deleteLinked(fs);
		   delete qbuff;
		   return 0;
	   }
   }
   Selection *ns=0;
   int sup=1;
   if((qi==1) && qx[ts].f){
	   if(qx[ts].rel && qx[ts].f->type == INDEX_TYPE){
		   int l;
		   Buffer *nq=new Buffer(l=(qx[ts].rel->getSize()+12));
		   nq->setSize(snprintf(*nq,l-1,"order by %s",(char*)*qx[ts].rel)+1);
		   selections[sin]=selectByRelation(qx[ts].f,nq);
		   if(selections[sin])
			   qi++;
	   }else{
		   if(fs==0){
			   if((b=getSelectionFromCache(qx[ts].f,FROMTO,0,0))!=0){
				   Selection *s=new Selection();
				   s->putStore(b);
				   selections[sin]=s;
			   }
		   }
		   if(selections[sin]==0)
			   selections[sin]=new Range(this,0,0,qx[ts].f,FROMTO,fs?(qx[ts].m&ORDER?-1:1):0,fs);
		   qi++;
	   }
	   delete qx[ts].rel;
	   qx[ts].f=0;
	   if(qi==2){
		   sortby=sin;
		   sin++;
		   sup=0;
		   qx[ts].m|=AND;
	   }
   }
   if(sortby==-1)
	   sortby=alt;
   if(sin==1 && likes==0){
	   if(subset==0){
		   ns=selections[0];
		   if (sortby==-1)
			   ns->sort();
		   ns->setOrder((qx[1].m&ORDER)?-1:1);
		   deleteLinked(fs);
		   delete qbuff;
		   return ns;
	   }else{
		   if(addsubset==0){
			   selections[sin]=new Selection();
			   selections[sin]->putStore(subset);
			   subset=0;
			   if(sortby==-1)
				   sortby=sin;
			   sin++;
			   qx[ts].m|=AND;
		   }
	   }
   }
   if((qx[ts].m&AND)==0){
	   if(addsubset && subset){
		   selections[sin]=new Selection();
		   selections[sin++]->putStore(subset);
		   subset=0;
	   }
   	   int totl=0;
	   int items=0;
	   int *sl=0;
	   Buffer* ms=0;
	   if(likes){
		   for(int i=0;i<ts;++i){
			   if(qx[i].m==LIKES && qx[i].f!=0 && qx[i].v!=0){
				   Buffer *m=0;
				   if(subset==0)
					   m=dbf->getValidList();
				   else
					   m=new Buffer(*subset,subset->getSize());
				   selections[sin]=madSearch(*qx[i].v,m,qx[i].f);
				   if(selections[sin]!=0)
					   sin++;
				   delete qx[i].v;
				   qx[i].f=0;
				   qx[i].v=0;
			   }
		   }
	   }
	   if(qx[ts].f!=0){
		   sortby=0;
		   if((qx[ts].f->type==INDEX_TYPE) && qx[ts].rel!=0){
			   int l;
			   Buffer *nq=new Buffer(l=(qx[ts].rel->getSize()+12));
			   nq->setSize(snprintf(*nq,l-1,"order by %s",(char*)*qx[ts].rel)+1);
			   Selection *star=selectByRelation(qx[ts].f,nq);
			   if(star){
				   ms=star->getBuffer();
				   delete star;
			   }
			   delete qx[ts].rel;
		   }else{
			   if (fs==0){
				   ms=getSelectionFromCache(qx[ts].f,FROMTO,0,0);
			   }
			   if(ms==0){
				   Selection* star=new Range(this,0,0,qx[ts].f,FROMTO,fs?(qx[ts].m&ORDER?-1:1):0,fs);
				   if(star){
					   ms=star->getBuffer();
					   delete star;
				   }
			   }
		   }
	   }else{
		   if(subset){
			   ms=subset;
			   subset=0;
		   }
	   }
	   numList *nl=new numList(256);
	   int k;
	   for(k=0;k<sin;++k){
		   if(selections[k]){
			   Buffer *m=selections[k]->getBuffer();
			   if(m){
                   int *x=(int*)((char*)*m);
                   int bs=m->getSize()/sizeof(int);
				   for(int j=0;j<bs;++j){
					   int pos;
					   if(nl->getPos(x[j],&pos)==0){
						   nl->insert(pos,x[j]);
					   }
				   }
				   delete m;
			   }
			   delete selections[k];
			   selections[k]=0;
		   }
	   }
	   Buffer *m=0;
	   items=nl->getSize();
	   if(items>0){
		   m = new Buffer(items);
		   memcpy(*m,(int*)*nl,items);
		   items/=sizeof(int);
	   }
	   delete nl;
	   if(ms==0){
		   ns=new Selection();
		   ns->putStore(m);
	   }else{
		   items=0;
		   if(m==0){
			   delete subset;
		   }else{
			   sl=(int*)((char*)*ms);
			   totl=ms->getSize()/sizeof(int);
			   if(subset){
				   sortList(subset);
				   for(int j=0;j<totl;++j)
					   if(findinList(subset,sl[j])==0)
						   sl[j]=0;
					   delete subset;
			   }
			   for(k=0;k<totl;++k){
				   if(sl[k]){
					   if(findinList(m,sl[k])){
						   items++;
					   }
					   else
						   sl[k]=0;
				   }
			   }
			   delete m;
			   if(items){
				   m=new Buffer(sizeof(int)*items);
				   int *x=(int*)((char*)*m);
				   for(int n=0,k=0;n<items;k++){
					   if(sl[k])
						   x[n++]=sl[k];
				   }
				   ns=new Selection();
				   ns->putStore(m);
			   }
		   }
		   delete ms;
	   }      
	   if(ns){
		   if (sortby==-1)
			   ns->sort();
		   ns->setOrder((qx[ts].m&ORDER)?-1:1);
	   }
	   delete qbuff;
	   deleteLinked(fs);
	   return ns;
   }
   if(subset && (addsubset==0)){
	   selections[sin]=new Selection();
	   selections[sin]->putStore(subset);
	   subset=0;
	   if(sortby==-1)
		   sortby=sin;
	   sin++;
   }
   if(qx[ts].f){
	   if(qx[ts].f->type==INDEX_TYPE && qx[ts].rel!=0){
		   int l;
		   Buffer *nq=new Buffer(l=(qx[ts].rel->getSize()+12));
		   nq->setSize(snprintf(*nq,l-1,"order by %s",(char*)*qx[ts].rel)+1);
		   selections[sin]=selectByRelation(qx[ts].f,nq);
		   if(selections[sin]){
			   sortby=sin;
			   sin++;
		   }
		   delete qx[ts].rel;
	   }else{
		   if(fs==0){
			   if((b=getSelectionFromCache(qx[ts].f,FROMTO,0,0))!=0){
				   Selection *s=new Selection();
				   s->putStore(b);
				   selections[sin]=s;
			   }
		   }
		   if(selections[sin]==0)
			   selections[sin]=new Range(this,0,0,qx[ts].f,FROMTO,fs?(qx[ts].m&ORDER?-1:1):0,fs);
		   sortby=sin;
		   sin++;
	   }
	   if(sin==2)
		   sup=0;
   }
   Selection *su=0;
   if((sin>1) && sup){
	   int z=-1;
	   for(int j=0;j<sin;++j){
		   if(selections[j] && selections[j]->isUnique()){
			   if(z==-1){
				   z=j;
			   } else{
				   z=-1;
				   break;
			   }
		   }
	   }
	   if(z!=-1){
		   su=selections[z];
		   selections[z]=0;
	   }
   }
   int min=sortby;
   if(min==-1 || selections[min]==0){
	   min=0;
	   for(int j=0;j<sin;++j)
		   if(selections[j] && ((selections[min]==0) || selections[j]->getTotal()<selections[min]->getTotal()))
			   min=j;
   }
   if(selections[min]!=0){
	   Buffer *slb=selections[min]->getBuffer();
	   int totl=selections[min]->getTotal();
	   delete selections[min];
	   selections[min]=0;
	   int items=0;
	   int *sl=0;
	   if(slb!=0){
		   items=totl;
		   sl=(int*)((char*)*slb);
		   while(1){
			   int z=-1;
			   for(int j=0;j<sin;++j){
				   if(selections[j]!=0){
					   if((z==-1) || (selections[j]->getTotal()<selections[z]->getTotal()))
						   z=j;
				   }
			   }
			   if(z==-1)
				   break;
			   Buffer* m=selections[z]->getBuffer();
			   delete selections[z];
			   selections[z]=0;
			   if(m==0)
				   items=0;
			   if(items==0){
				   delete m;
				   continue;
			   }
			   sortList(m);
			   items=0;
			   for(int n=0;n<totl;++n){
				   if(sl[n]){
					   if(findinList(m,sl[n])==0)
						   sl[n]=0;
					   else
						   items++;
				   }
			   }
			   delete m;
		   }
	   }
	   if(items && sl){
		   Buffer *m=0;
		   if(su && ((m=su->getBuffer())!=0)){
			   int st=su->getTotal();
			   Field* fu=su->getField();
			   int *c=(int*)((char*)*m);
			   int fo=getFieldOffset(fu);
			   int j=0;
			   for(int k=0;k<st;++k){
				   Buffer *eb=0;
				   Buffer *tb=new Buffer(getRecordSize());
				   char *tmp=*tb;
				   lock();
				   if(getRecordFromCache(c[k],tb))
					   eb=getEqualsBuffer(tmp+fo,fu,c[k]);
				   delete tb;
				   release();
				   if(eb!=0){
					   int found=0;
					   int et=eb->getSize()/sizeof(int);
					   for(int n=0; et > 0 && n < totl;++n){
						   if(sl[n]!=0){
							   if(findinList(eb,sl[n])){
								   if(found==0){
									   c[j++]=sl[n];
									   if((st-k)==1)
										   break;
									   found=1;
								   }
								   sl[n]=0;
								   et--;
							   }
						   }
					   }
					   delete eb;
				   }
			   }
			   m->setSize(j*sizeof(int));
		   }else{
			   m=new Buffer(sizeof(int)*items);
			   int *x=(int*)((char*)*m);
			   for(int n=0,k=0;n<items;k++){
				   if(sl[k])
					   x[n++]=sl[k];
			   }
		   }
		   if(sortby==-1)
			   sortList(m);
		   ns=new Selection();
		   ns->putStore(m);
		   ns->setOrder((qx[ts].m&ORDER)?-1:1);
	   }
	   delete slb;
   }
   int j;
   for(j=0;j<sin;++j)
	   delete selections[j];
   delete su;
   if(likes){
	   if(ns==0 && sin==0){
		   ns=new Selection();
		   ns->putStore(dbf->getValidList());
	   }
	   for(j=0;j<ts;++j){
		   if(qx[j].m==LIKES && qx[j].f!=0 && qx[j].v!=0){
			   if(ns){
				   Buffer *m=ns->getBuffer();
				   delete ns;
				   ns=madSearch(*qx[j].v,m,qx[j].f);
			   }
			   delete qx[j].v;
		   }
	   }
   }
   deleteLinked(fs);
   delete qbuff;
   if(subset && addsubset){
	   Buffer* ms=ns->getBuffer();
	   if(subset->getSize()>ms->getSize()){
		   Buffer *ts=ms;
		   ms=subset;
		   subset=ts;
	   }
	   sortList(ms);
	   int *sl=(int*)((char*)*ms);
	   int totl=ms->getSize()/sizeof(int);
   	   numList *nl=new numList(sl,totl);
   	   sl=(int*)((char*)*subset);
	   totl=subset->getSize()/sizeof(int);
	   int pos;
	   for(j=0;j<totl;++j){
		   if(nl->getPos(sl[j],&pos)==0){
			   nl->insert(pos,sl[j]);
		   }
	   }
	   delete ms;
	   delete subset;
	   Buffer *m=0;
	   totl=nl->getSize();
	   if(totl>0){
		   m = new Buffer(totl);
		   memcpy(*m,(int*)*nl,totl);
	   }
	   delete nl;
	   ns->putStore(m);
   }
   return ns;
}
*/



/*

  Selection* Table::selectByRelation(Field *f,Buffer* query)
{
	Selection* s=0;
	if(f->type==INDEX_TYPE){
		int cid=dbms->openDB(dbname);
		if(cid){
			Table *t=dbms->selectTable(cid,f->tableName);
			if(t){
				s=t->getSelection(query);
				query=0;
				if(s!=0){
					Buffer *m=s->giveBuffer();
					delete s;
					s=new Selection();
					s->putStore(m);
					s->setRelation(f);
					Buffer *m=s->giveBuffer();
					delete s;
					s=new Selection();
					s->setRelation(f);
					s->putStore(m);
					Buffer *mb=s->giveBuffer();
					delete s;
					s=0;
					if(mb!=0){
						int *x=(int*)((char*)*mb);
						int total=mb->getSize()/sizeof(int);
						int st=dbf->getTotal();
						if(st>0){
							Buffer *sb=new Buffer(sizeof(int)*st);
							char *ex=*sb;
							for(int i=0;i<total;++i){
								Buffer *eb=getEqualsBuffer((char*)(x+i),f);
								if(eb!=0){
									int cs=eb->getSize();
									memcpy(ex,*eb,cs);
									ex+=cs;
									delete eb;
								}
							}
							int n=ex-(char*)*sb;
							if(n>0){
								if(n<sb->getSize()){
									Buffer *tmp=new Buffer(*sb,n);
									delete sb;
									sb=tmp;
								}
								s=new Selection();
								s->putStore(sb);
							}else
								delete sb;
						}
						delete mb;				
					}

				}
			}
		}
		dbms->closeDB(cid);
	}
	delete query;
	return s;
}


int Table::getFieldAny(queryStruct* qx,char* fieldname,LinkedBuffer* tablelist,int cid)
{
	Field *f=getField(fieldname);
	if(f!=0){
		qx->f=f;
		return 1;
	}else{
		int n;
		for(n=0;fieldname[n]!=0;++n){
			if(fieldname[n]=='.'){
				fieldname[n]=0;
				f=getField(fieldname);
				fieldname[n]='.';
				if(f && f->type==INDEX_TYPE){
					qx->f=f;
					qx->rel=new Buffer(fieldname,strlen(fieldname)+1);
				}
				return f!=0;
			}
		}
		if(cid==0)
			cid=dbms->openDB(dbname);
		int rc=0;
		if(cid){
			for( SField *sf=fields;sf!=0; sf = (SField *)(((Field *)*sf) ->next)){
				if(((Field *)*sf)->type==INDEX_TYPE){
					LinkedBuffer *tn=tablelist;
					for(;tn!=0;tn=tn->next){
						if(stricmp(*tn,((Field *)*sf)->tableName)==0)
							break;
					}
					if(tn==0){
						Table *t=dbms->selectTable(cid,((Field *)*sf)->tableName);
						if(t){
							LinkedBuffer* tl=new LinkedBuffer(new Buffer(tableName,strlen(tableName)+1));
							tl->next=tablelist;
							rc=t->getFieldAny(qx,fieldname,tl,cid);
							delete tl;
							if(rc){
								qx->f=((Field *)*sf);
								if(qx->rel==0){
									qx->rel=new Buffer(n=(strlen(fieldname)+strlen(((Field *)*sf)->fieldName)+2));
									snprintf(*qx->rel,n,"%s.%s",((Field *)*sf)->fieldName,fieldname);
								}else{
									Buffer *tmp=new Buffer(n=(qx->rel->getSize()+strlen(((Field *)*sf)->fieldName)+1));
									snprintf(*tmp,n,"%s.%s",((Field *)*sf)->fieldName,(char*)*qx->rel);
									delete qx->rel;
									qx->rel=tmp;
								}
								break;
							}
						}
					}
				}
			}
			if(tablelist==0)
				dbms->closeDB(cid);
		}
		return rc;
	}
}
*/
